Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lect6.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
344 Кб
Скачать
☆

Оголошення вказівників в мові програмування c-51*.

Вказівник - це змінна, яка може містити адресу іншої змінної. Вказівник може бути використаний для роботи із змінній, адресу якої він містить. Використання вказівників дозволяє реалізувати ефективнішу обробку масивів, структур, а також реалізовувати підпрограми, які працюватимуть над різними областями пам'яті мікроконтролера. Для цього в підпрограму потрібно тільки передати початкову адресу оброблюваної області пам'яті.

Для ініціалізації вказівника (записи початкової адреси змінної) можна використовувати ідентифікатор змінної, при цьому як ідентифікатор може виступати ім'я змінної, масиву, структури, літерального рядка.

При оголошенні змінній - покажчика, необхідно визначити тип об'єкту даних, адреса яких міститиме змінна, і ім'я покажчика з попередньою зірочкою (або групою зірочок). Формат оголошення покажчика:

специфікатор-тіпа [ модифікатор ] *описатель.

Специфікатор-тіпа задає тип об'єкту і може бути будь-якого основного типу, структури або суміші (про ці типи буде сказано нижче). Задаючи замість специфікатора-типу ключове слово void, можна відстрочити визначення типу, на який посилається покажчик. Змінна, що оголошується як покажчик на тип void, може бути використана для посилання на об'єкт будь-якого типу. Проте для того, щоб можна було виконати арифметичні і логічні операції над покажчиками або над об'єктами, на які вони указують, необхідно при виконанні кожної операції явно визначити тип об'єктів. Такі визначення типів можуть бути виконані за допомогою операції приведення типів.

Приклади оголошення вказівників на різні типи змінних:

unsigned int * ptr; /* переменная ptr представляет собой указатель на целую беззнаковую) переменную*/

float * x; /* переменная х указывает на переменную с плавающей точкой*/

char *buffer ; /*объявляется указатель с именем buffer который указывает на символьную переменную*/

Тепер для того, щоб почати працювати з цими покажчиками досить їх ініціалізувати. Наприклад:

ptr=&A; //Присвоить адрес переменной A

*ptr=2+2;//Работаем с переменной A

a=&B;

*ptr=3*4;//А теперь работаем с переменной B

Як модифікатори при оголошенні покажчика можуть виступати ключові слова const, data, idata, xdata, code. Ключове слово const указує, що покажчик не може бути змінений в програмі. Розмір змінної, оголошеної як покажчик, залежить від модифікатора і використовуваного виду пам'яті, для якої компілюватиметься програма. Покажчики на різні типи даних не обов'язково повинні мати однакову довжину.

Для модифікації розміру покажчика можна використовувати ключові слова data, idata, xdata, code.

Задаючи замість специфікатора типа, ключове слово void, можна відстрочити визначення типу, на який посилається покажчик. Змінна, що оголошується як покажчик на тип void, може бути використана для посилання на об'єкт будь-якого типу. Проте для того, щоб можна було виконати арифметичні і логічні операції над покажчиками або над об'єктами, на які вони указують, необхідно при виконанні кожної операції явно визначити тип об'єктів. Такі визначення типів можуть бути виконані за допомогою операції приведення типів.

float nomer;

void *addres;

addres = &nomer;

(float *)addres ++;

/* Переменная addres объявлена как указатель на объект любого типа.

Поэтому ей можно присвоить адрес любого объекта (& - операция

вычисления адреса). Однако, как было отмечено выше, ни одна

арифметическая операция не может быть выполнена над указателем,

пока не будет явно определен тип данных, на которые он указывает. Это

можно сделать, используя операцию приведения типа (float *) для

преобразования типа указателя addres к типу float. Затем оператор ++

отдаёт приказ перейти к следующему адресу.*/

Як модифікатори при оголошенні покажчика можуть виступати ключові слова const, data, idata, xdata, code. Ключове слово const указує, що покажчик не може бути змінений в програмі.

Унаслідок унікальності архітектури контроллера 8051 і його похідних компілятор С51 підтримує 2 види покажчиків: память-завісимиє і що не типізуються.

Покажчики, що не типізуються

Покажчики, що не типізуються, оголошуються точно так, як і покажчики в стандартній мові програмування C. Для того, щоб не залежати від типу пам'яті, в якій може бути розміщена змінна, для покажчиків, що не типізуються, виділяється 3 байти. У першому байті указується вид пам'яті змінної, в другому байті - старший байт адреси, в третьому - молодший байт адреси змінної. Покажчики, що не типізуються, можуть бути використані для звернення до будь-яких змінних незалежно від типу пам'яті мікроконтролера. Саме тому багато бібліотечних функцій мови програмування C51 використовують покажчики цього типу, при цьому їм абсолютно неважливо, в якій саме області пам'яті розміщуються змінні. Приведемо лістинг, в якому відображаються особливості трансляції покажчиків, що не типізуються:

stmt level source

1 char *c_ptr; /* char ptr */

2 int *i_ptr; /* int ptr */

3 long *l_ptr; /* long ptr */

4

5 void main (void)

6 {

7 1 char data dj; /*переменные во внутренней памяти данных data */

8 1 int data dk;

9 1 long data dl;

10 1

11 1 char xdata xj; /*переменные во внешней памяти данных xdata */

12 1 int xdata xk;

13 1 long xdata xl;

14 1

15 1 char code cj = 9; /*переменные в памяти программ code */

16 1 int code ck = 357;

17 1 long code cl = 123456789;

18 1

19 1 /*настроим указатели на внутреннюю память данных data */

20 1 c_ptr = &dj;

21 1 i_ptr = &dk;

22 1 l_ptr = &dl;

23 1 /*настроим указатели на внешнюю память данных xdata */

24 1 c_ptr = &xj;

25 1 i_ptr = &xk;

26 1 l_ptr = &xl;

27 1 /*настроим указатели на память программ code */

28 1 c_ptr = &cj;

29 1 i_ptr = &ck;

30 1 l_ptr = &cl;

31 1 }

Пам'ять залежні покажчики

У оголошення память-завісимих покажчиків завжди включається модифікатор пам'яті. Звернення завжди відбувається до вказаної області пам'яті, наприклад:

char data *str; /*указатель на строку во внутренней памяти данных data */

int xdata *numtab; /*указатель на целую во внешней памяти данных xdata */

long code *powtab; /*указатель на длинную целую в памяти программ code */

Оскільки модель пам'яті визначається під час компіляції, покажчикам, що типізуються, не потрібний байт, в якому указується тип пам'яті мікроконтролера. Тому програма з використанням покажчиків, що типізуються, буде коротша і виконуватиметься швидше в порівнянні з програмою, що використовує покажчики, що не типізуються. Покажчики, що типізуються, можуть мати розмір в 1 байт (покажчики на пам'ять idata, data, bdata, і pdata) або в 2 байти (покажчики на пам'ять code і xdata).

Оголошення нових типів змінних

У мові програмування C-51 є можливість наперед оголосити тип змінної, а потім скористатися їм при оголошенні змінних. Використання наперед оголошеного типу дозволяє при оголошенні змінній скоротити його довжину, уникнути помилок при оголошенні змінних в різних місцях програми і добитися повної ідентичності оголошуваних змінних.

Оголосити новий тип змінної можна двома способами. Перший спосіб - вказати ім'я типу при оголошенні структури, об'єднання або перерахування, а потім використовувати це ім'я в оголошенні змінних і функцій. Другою - використовувати для оголошення типу ключове слово typedef.

При оголошенні типу з ключовим словом typedef, ідентифікатор стоїть на місці описуваного об'єкту, є ім'ям оголошуваного типу даних, і далі цей тип може бути використаний для оголошення змінних.

Відзначимо, що будь-який тип може бути оголошений з використанням ключового слова typedef, включаючи типи покажчиків, функцій або масивів. Ім'я з ключовим словом typedef для типів покажчика, структури, об'єднання може бути оголошено перш ніж ці типи будуть визначені, але в межах видимості об'явника.

Приклади оголошення і використання нових типів:

typedef

float

(* MATH)( ); // MATH - новое имя типа, представляющее указатель на функцию, возвращающую значения типа float

typedef

char

FIO[40] // FIO - массив из сорока символов

MATH cos; // cos  указатель на функцию, возвращающую значения типа  double

// Можно провести эквивалентное объявление

float

(* cos)( );

FIO person; //Переменная person - массив из сорока символов

// Это эквивалентно объявлению

char

person[40];

При оголошенні змінних і типів тут були використані імена типів (MATH FIO). Крім оголошення змінних, імена типів можуть ще використовуватися в трьох випадках: у списку формальних параметрів при оголошенні функцій, в операціях приведення типів і в операції sizeof .

Ініціалізація даних

У мові програмування C-51, як і в інших версіях мови C при оголошенні змінній їй можна привласнити початкове значення, приєднуючи ініціатор до описувача. При цьому під час запуску Вашої програми в елементи пам'яті, відповідні цим змінним будуть записані початкові значення. Тільки після цього виконання програми буде передано підпрограмі main();.

Ініціатор змінної починається із знаку "=" і може бути записаний в наступних форматах:

Формат 1: = ініціатор;

Формат 2: = { список - ініціаторів };

Формат 1 використовується при ініціалізації змінних основних типів і покажчиків, а формат 2 - при ініціалізації складених об'єктів.

Приклади привласнення первинних значень простим змінним:

char tol = 'N'; //Переменная tol инициализируется символом 'N'.

const long megabyte = (1024*1024);

Змінною megabyte, що не модифікується, привласнюється значення константного виразу, після чого ця змінна не може бути змінена. Відзначу, що для мікроконтролерів сімейства MCS-51 внутрішня пам'ять є дефіцитним ресурсом, тому використовувати її для зберігання констант нераціонально. Краще оголосити змінну із специфікатором типу пам'яті code.

static int b[2][2] = {1,2,3,4};

Ініціалізувався двомірний масив b цілих величин, елементам масиву привласнюються значення із списку. Ця ж ініціалізація може бути виконана таким чином:

static int b[2][2] = { { 1,2 }, { 3,4 } };

При ініціалізації масиву можна опустити одну або декілька размерностей

static int

b[3] = { { 1,2 }, { 3,4 } };

Якщо при ініціалізації вказано менше значень для рядків, то елементи, що залишилися, ініціалізувалися 0, тобто при описі

static int b[2][2]= { { 1,2 }, { 3 } };

елементи першого рядка отримають значення 1 і 2, а другою 3 і 0.

При ініціалізації складених об'єктів, потрібно уважно стежити за використанням дужок і списків ініціалізацій.

Приклади:

struct complex

{float real;

float imag;

}comp[2][3]={{{1,1},{2,3},{ 4, 5}},

{{6,7},{8,9},{10,11}}

};

У даному прикладі ініціалізувався масив структур comp з двох рядків і трьох стовпців, де кожна структура складається з двох елементів real і imag.

struct

complex comp2 [2][3] = { {1,1},{2,3},{4,5},{6,7},{8,9},{10,11} };

В даному прикладі компілятор інтерпретує дані фігурні дужки таким чином:

· перша ліва фігурна дужка - початок складеного ініціатора для масиву comp2;

· друга ліва фігурна дужка - початок ініціалізації першого рядка масиву comp2[0]. Значення 1,1 привласнюються двом елементам першої структури;

· перша права дужка (після 1) указує компілятору, що список ініціаторів для рядка масиву закінчений, і елементи структур, що залишилися, в рядку comp[0] автоматично ініціалізувалися нулем;

· аналогічно список {2,3} ініціалізував першу структуру в рядку comp[1], а структури масиву, що залишилися, звертаються в нулі;

· на наступний список ініціалізацій {4,5} компілятор повідомлятиме про можливу помилку оскільки рядок 3 в масиві comp2 відсутній.

При ініціалізації об'єднання задається значення першого елементу об'єднання відповідно до його типу.

Приклад:

union tab

{unsigned char name[10];

int tab1;

}pers={'A','H','T','O','H'};

Ініціалізувалася змінна pers.name, і так як це масив, для його ініціалізації потрібний список значень у фігурних дужках. Перші п'ять елементів масиву ініціалізувалися значеннями із списку, інші нулями.

Ініціалізацію масиву символів можна виконати за допомогою літерального рядка.

char stroka[ ] = "привет";

Ініціалізувався масив символів з 7 елементів, останнім елементом (сьомим) буде символ '\0', яким завершуються всі літеральні рядки.

У випадку, якщо задається розмір масиву, а літеральний рядок довший, ніж розмір масиву, то зайві символи відкидаються. Наступне оголошення ініціалізувало змінну stroka як масив, що складається з семи елементів.

char stroka[5]="привет";

У змінну stroka потрапляють перші п'ять елементів літерала, а символи 'т' і '\0' відкидаються. Якщо рядок коротший за розмірність масиву, то елементи масиву, що залишилися, заповнюються нулями. Відзначимо, що ініціалізація змінної типу tab може мати наступний вигляд:

union tab pers1="Антон";

і, таким чином, в символьний масив потраплять символи:

'А','Н','Т','О','Н','\0',

а в решту елементів будуть записані нулі.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]