Указатель — это переменная, которая может содержать адрес другой переменной. Указатель может быть использован для работы с переменной, адрес которой он содержит. Использование указателей позволяет реализовать более эффективную обработку массивов, структур, а также реализовывать подпрограммы, которые будут работать над различными областями памяти микроконтроллера. Для этого в подпрограмму нужно только передать начальный адрес обрабатываемой области памяти.
Для инициализации указателя (записи начального адреса переменной) можно использовать идентификатор переменной, при этом в качестве идентификатора может выступать имя переменной, массива, структуры, литеральной строки.
При объявлении переменной — указателя, необходимо определить тип объекта данных, адрес которых будет содержать переменная, и имя указателя с предшествующей звездочкой (или группой звездочек). Формат объявления указателя:
спецификатор-типа [ модификатор ] *описатель.
Спецификатор-типа задает тип объекта и может быть любого основного типа, структуры или смеси (об этих типах будет сказано ниже). Задавая вместо спецификатора-типа ключевое слово 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 }
ASSEMBLY LISTING OF GENERATED OBJECT CODE
; FUNCTION main (BEGIN)
; SOURCE LINE # 5
; SOURCE LINE # 6
; SOURCE LINE # 20
0000 750000 R MOV c_ptr,#00H
0003 750000 R MOV c_ptr+01H,#HIGH dj
0006 750000 R MOV c_ptr+02H,#LOW dj
; SOURCE LINE # 21
0009 750000 R MOV i_ptr,#00H
000C 750000 R MOV i_ptr+01H,#HIGH dk
000F 750000 R MOV i_ptr+02H,#LOW dk
; SOURCE LINE # 22
0012 750000 R MOV l_ptr,#00H
0015 750000 R MOV l_ptr+01H,#HIGH dl
0018 750000 R MOV l_ptr+02H,#LOW dl
; SOURCE LINE # 24
001B 750001 R MOV c_ptr,#01H
001E 750000 R MOV c_ptr+01H,#HIGH xj
0021 750000 R MOV c_ptr+02H,#LOW xj
; SOURCE LINE # 25
0024 750001 R MOV i_ptr,#01H
0027 750000 R MOV i_ptr+01H,#HIGH xk
002A 750000 R MOV i_ptr+02H,#LOW xk
; SOURCE LINE # 26
002D 750001 R MOV l_ptr,#01H
0030 750000 R MOV l_ptr+01H,#HIGH xl
0033 750000 R MOV l_ptr+02H,#LOW xl
; SOURCE LINE # 28
0036 7500FF R MOV c_ptr,#0FFH
0039 750000 R MOV c_ptr+01H,#HIGH cj
003C 750000 R MOV c_ptr+02H,#LOW cj
; SOURCE LINE # 29
003F 7500FF R MOV i_ptr,#0FFH
0042 750000 R MOV i_ptr+01H,#HIGH ck
0045 750000 R MOV i_ptr+02H,#LOW ck
; SOURCE LINE # 30
0048 7500FF R MOV l_ptr,#0FFH
004B 750000 R MOV l_ptr+01H,#HIGH cl
004E 750000 R MOV l_ptr+02H,#LOW cl
; SOURCE LINE # 31
0051 22 RET
; FUNCTION main (END)