Объявление массивов в языке программирования C-51 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Объявление массивов в языке программирования C-51



При обработке данных достаточно часто приходится работать с рядом переменных одинакового типа (и описывающих одинаковые объекты). В этом случае эти переменные имеет смысл объединить одним идентификатором. Это позволяют сделать массивы.

Массивы — это группа элементов одинакового типа (float, char, int и т.п.). Из объявления массива компилятор должен получить информацию о типе элементов массива и их количестве. Объявление массива имеет два формата:

 

спецификатор-типа описатель [константное-выражение];
спецификатор-типа описатель [ ];Описатель - это идентификатор массива.

Спецификатор-типа задает тип элементов объявляемого массива. Элементами массива не могут быть функции и элементы типа void.

Константное-выражение в квадратных скобках задает количество элементов массива. Константное-выражение при объявлении массива может быть опущено в следующих случаях:

70. при объявлении массив инициализируется,

71. массив объявлен как формальный параметр функции,

72. массив объявлен как ссылка на массив, явно определенный в другом файле.

В языке С-51 определены только одномерные массивы, но поскольку элементом массива может быть массив, можно определить и многомерные массивы. Они формализуются списком константных-выражений, следующих за идентификатором массива, причем каждое константное-выражение заключается в свои квадратные скобки.

Каждое константное-выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два константных-выражения, трехмерного — три и т.д. Отметим, что в языке С‑51 первый элемент массива имеет индекс равный 0.

Примеры:

 

int a[2][3]; /* представлено в виде матрицы a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] */ float b[10]; /* вектор из 10 элементов имеющих тип double */ int w[3][3] = { { 2, 3, 4 }, { 3, 4, 8 }, { 1, 0, 9 } };

В последнем примере объявлен массив w[3][3]. Списки, выделенные в фигурные скобки, соответствуют строкам массива, в случае отсутствия скобок инициализация будет выполнена неправильно.

В языке С‑51 можно использовать сечения массива, как и в других языках высокого уровня (PLM и т.п.), однако на использование сечений накладывается ряд ограничений. Сечения формируются вследствие опускания одной или нескольких пар квадратных скобок. Пары квадратных скобок можно отбрасывать только справа налево и строго последовательно. Сечения массивов используются при организации вычислительного процесса в функциях языка С‑51, разрабатываемых пользователем.

Примеры использования сечений массивов:

Пусть объявлен массив S:

 

int s[2][3];

Если при обращении к некоторой функции написать s[0], то в эту функцию будет передаваться нулевая строка массива s.

 

int b[2][3][4];

При обращении к массиву b можно написать, например, b[1][2] и будет передаваться вектор из четырех элементов, а обращение b[1] даст двухмерный массив размером 3 на 4. Нельзя написать b[2][4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограничению, наложенному на использование сечений массива.

Для работы с символьными строками в языке программирования C используются массивы символов, например:

 

char str[] = "объявление массива символов";

 

Следует учитывать, что в символьной строке находится на один элемент больше, так как последним элементом строки должен быть ‘\0’. В этом примере использовано неявное задание длины массива символов. Это стало возможным, так как массиву сразу присваивается конкретное значение.

При написании программ для микроконтроллеров семейства MCS‑51 такое задание массива может привести к неоправданному расходу внутренней памяти данных, а эта память в микроконтроллере составляет всего 120 байт. Поэтому лучше воспользоваться размещением строки в памяти программ, как это показано в следующем примере:

 

char code str[] = "объявление массива символов";

Структуры

Работа с массивами облегчает понимание и написание программы, когда для обозначения похожих элементов используется один идентификатор. Однако в ряде случаев приходится обрабатывать разнородные элементы, описывающие один объект. В этом случае вместо массива используется структура.

Структура — это составной объект, в который входят элементы любых типов, за исключением функций. В отличие от массива, который является однородным объектом, структура может быть неоднородной. Тип структуры определяется записью вида:

 

struct { список описаний}

В структуре обязательно должен быть указан хотя бы один компонент. Компоненты структуры называются полями структуры. Объявление полей производится в следующем виде:

 

тип-данных описатель;

где тип-данных указывает тип структуры для объектов, определяемых в описателях. В простейшей форме описатели представляют собой идентификаторы переменных или массивов.

Пример объявления структур:

 

struct//Описание типа структуры------------------------- {char tzvet,//Цвет точки int x, //Координата X y; //Координата Y }//------------------------------------------------------ tochka1, tochka2, //Переменные, обозначающие точки дисплея simv[7][9]; //Переменная, содержащая рисунок символа struct {int year; //Поле структуры, в котором хранится год char moth, //Поле структуры, в котором хранится месяц day; //Поле структуры, в котором хранится день }//------------------------------------------------------- date1, date2;//Переменные, обозначающие две различных даты

Переменные tochka1, tochka2 объявляются как структуры, каждая из которых состоит из трех полей tzvet, х и у. Переменная simv объявляется как двумерный массив, состоящий из 63 переменных, описывающих точку дисплея. Во втором объявлении каждая из двух переменных date1, date2 состоит из трех компонентов year, moth, day.

Существует и другой способ связывания имени переменной с типом структуры, он основан на использовании отдельного объявления типа структуры. Тип структуры описывается следующим образом:

 

struct тип-структуры { список описаний; };

где тип-структуры является идентификатором типа объявляемой структуры и может быть использован для последующего объявления структур данного вида (то есть содержащих точно такие же поля) в форме:

struct тип-структуры список-идентификаторов;

В приведенном ниже примере идентификатор student описывается как тип структуры:

 

struct student {char name[25];//Имя и фамилия студента int id, //Номер в журнале age; //Возраст char usp; //успеваемость };

Пример:

 

struct student st1[23];//объявление массива переменных типа студент

Доступ к полям структуры осуществляется с помощью указания имени структуры и следующего через точку имени поля, например:

 

st[1].name="Иванов"; st[1].id=2; st[1].age=23;

Поля битов

Элементом структуры может быть битовое поле, обеспечивающее доступ к отдельным битам памяти. Вне структур битовые поля объявлять нельзя. Нельзя также организовывать массивы битовых полей и нельзя применять к полям операцию определения адреса. В общем случае тип структуры с битовым полем задается в следующем виде:

 

struct { unsigned идентификатор 1: длина-поля 1; unsigned идентификатор 2: длина-поля 2; }

длина-поля задается целым выражением или константой. Эта константа определяет число битов, отведенное соответствующему полю. Поле нулевой длины обозначает выравнивание на границу следующего слова.

Пример:

 

struct {unsigned R: 1;//Флаг приёма байта unsigned T: 1;//Флаг передачи байта unsigned Cmd:5;//Поле команды unsigned St: 1;//Поле статуса} Cntr;

Структуры битовых полей могут содержать и знаковые компоненты. Такие компоненты автоматически размещаются на соответствующих границах слов, при этом некоторые биты слов могут оставаться неиспользованными.

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

 

Cntr.Cmd=30;

Следует отметить, что, несмотря на то, что язык программирования C‑51, как наследник стандартного языка программирования C, позволяет использовать поля битов, лучше для битовых переменных использовать специализированный тип переменных bit, размещаемых в пространстве битовой адресации.

Объединения (смеси)

Главной особенностью объединения является то, что для каждого из объявленных элементов этого объединения выделяется одна и та же область памяти, т.е. они перекрываются. Хотя доступ к этой области памяти возможен с использованием любого из элементов, элемент для этой цели должен выбираться так, чтобы полученный результат не был бессмысленным.

Объединение применяется для следующих целей:

73. использования одного и той же области памяти для размещения переменных различного типа;

74. интерпретации представления переменной одного типа, как несколько переменных другого типа.

Объединение по описанию подобно структуре. Тип объединения может задаваться в следующем виде:

 

union { описание элемента 1;... описание элемента n; };

Доступ к элементам объединения осуществляется тем же способом, что и к структурам.

Память, которая соответствует переменной типа объединения, определяется величиной, необходимой для размещения наиболее длинного элемента объединения. Когда используется элемент меньшей длины, то переменная типа объединения может содержать неиспользуемую память. Все элементы объединения хранятся в одной и той же области памяти, начиная с одного адреса.

Второй вариант можно проиллюстрировать следующим образом. Например, требуется передать число плавающего типа. Однако последовательный порт может передавать или принимать только однобайтовые числа. В этом случае можно воспользоваться объединением:

 

union {float Koeff; //Интерпретация объединения как переменной плавающего типа char byte[4];//Интерпретация объединения как массива }buffer; //Объявление переменной buffer

Объединение buffer позволяет последовательному порту получить отдельный доступ ко всем байтам числа buffer.Koeff начиная от младшего байта buffer.byte[0], и заканчивая старшим байтом buffer.byte[3]. В программе затем можно пользоваться загруженным числом как числом с плавающей запятой.

Объявление указателей в языке программирования C‑51

Указатель — это переменная, которая может содержать адрес другой переменной. Указатель может быть использован для работы с переменной, адрес которой он содержит. Использование указателей позволяет реализовать более эффективную обработку массивов, структур, а также реализовывать подпрограммы, которые будут работать над различными областями памяти микроконтроллера. Для этого в подпрограмму нужно только передать начальный адрес обрабатываемой области памяти.

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

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

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

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

Примеры объявления указателей на различные типы переменных:

 

unsigned int * ptr; /* переменная ptr представляет собой указатель на целую беззнаковую)
переменную*/float * x; /* переменная х указывает на переменную с плавающей точкой*/char *buffer; /*объявляется указатель с именем buffer который указывает на символьную
переменную*/

Теперь для того, чтобы начать работать с этими указателями достаточно их инициализировать.

Например:

 

ptr=&A; //Присвоить адрес переменной A*ptr=2+2;//Работаем с переменной Aa=&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 байта. В первом байте указывается вид памяти переменной, во втором байте — старший байт адреса, в третьем — младший байт адреса переменной. Нетипизированные указатели могут быть использованы для обращения к любым переменным независимо от типа памяти микроконтроллера. Именно поэтому многие библиотечные функции языка программирования C‑51 используют указатели этого типа, при этом им совершенно неважно, в какой именно области памяти размещаются переменные. Приведем листинг, в котором отображаются особенности трансляции нетипизированных указателей:

 

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 # 200000 750000 R MOV c_ptr,#00H0003 750000 R MOV c_ptr+01H,#HIGH dj0006 750000 R MOV c_ptr+02H,#LOW dj; SOURCE LINE # 210009 750000 R MOV i_ptr,#00H000C 750000 R MOV i_ptr+01H,#HIGH dk000F 750000 R MOV i_ptr+02H,#LOW dk; SOURCE LINE # 220012 750000 R MOV l_ptr,#00H0015 750000 R MOV l_ptr+01H,#HIGH dl0018 750000 R MOV l_ptr+02H,#LOW dl; SOURCE LINE # 24001B 750001 R MOV c_ptr,#01H001E 750000 R MOV c_ptr+01H,#HIGH xj0021 750000 R MOV c_ptr+02H,#LOW xj; SOURCE LINE # 250024 750001 R MOV i_ptr,#01H0027 750000 R MOV i_ptr+01H,#HIGH xk002A 750000 R MOV i_ptr+02H,#LOW xk; SOURCE LINE # 26002D 750001 R MOV l_ptr,#01H0030 750000 R MOV l_ptr+01H,#HIGH xl0033 750000 R MOV l_ptr+02H,#LOW xl; SOURCE LINE # 280036 7500FF R MOV c_ptr,#0FFH0039 750000 R MOV c_ptr+01H,#HIGH cj003C 750000 R MOV c_ptr+02H,#LOW cj; SOURCE LINE # 29003F 7500FF R MOV i_ptr,#0FFH0042 750000 R MOV i_ptr+01H,#HIGH ck0045 750000 R MOV i_ptr+02H,#LOW ck; SOURCE LINE # 300048 7500FF R MOV l_ptr,#0FFH004B 750000 R MOV l_ptr+01H,#HIGH cl004E 750000 R MOV l_ptr+02H,#LOW cl; SOURCE LINE # 310051 22 RET; FUNCTION main (END)

Память зависимые указатели

В объявления память зависимых указателей всегда включается модификатор памяти. Обращение всегда происходит к указанной области памяти, например:

 

char data *str; /*указатель на строку во внутренней памяти данных data */int xdata *numtab; /*указатель на целую во внешней памяти данных xdata */long code *powtab; /*указатель на длинную целую в памяти программ code */

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



Поделиться:


Последнее изменение этой страницы: 2017-02-07; просмотров: 251; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.149.255.162 (0.029 с.)