Россия, г. Москва |
Язык программирования Си
Соглашения об именах
Мы уже говорили, обсуждая программную документацию, что для текстов программ характерно однократное написание и многократное прочтение. Весьма значимым при чтении текста программы является отделение имен одного класса объектов от других. Проще всего для этого ввести некоторые соглашения об именах, например имена типов и констант писать ТОЛЬКО заглавными буквами, начинать определение имени без знаковых типов и буквы U (unsigned), перечислимых типов - с буквы E (enumeric) и тому подобное. Для этих целей можно воспользоваться следующими определениями:
typedef char CHAR; /* general text. Range 0..127 */ typedef unsigned char UCHAR; /* extended text. Range 0..255 */ typedef unsigned short BOOL; /* Time efficient Boolean */ typedef unsigned har TBOOL; /* Tiny (space efficient) Boolean */ typedef char TINY; /* 8 bit. Range (-2^7-1)..(+2^7) */ typedef unsigned char UTINY; /* 8 bit. Range (0)..(+2^8) */ typedef unsigned char TINYBITS; /* 8 bit. For bit manipulation use */ typedef short SHORT; /* 16 bit. Range (-2^15-1)..(+2^15) */ typedef unsigned short USHORT; /* 16 bit. Range (0)..(+2^16) */ typedef unsigned short SHORTBITS; /* 16 bit. For bit manipulation use */ typedef long LONG; /* 32 bit.Range (-2^31-1)..(+2^31)*/ typedef unsigned long ULONG; /* 32 bit.Range (0)..(+2^32) */ typedef unsigned long LONGBITS; /* 32 bit.For bit manipulation use */ typedef int INT; /* Natural machine size integer */
Как мы видим, один и тот же тип языка Си, например unsigned char, может быть многократно переопределен под различными именами в зависимости от целей его использования.
Типы, определяемые пользователем
Программисту позволяется вводить в программу свои собственные средства кодировки, приписывая каждому значению собственное имя (идентификатор). Для этого в языке Си введен перечислимый тип.
Перечислимые:
enum - перечисление констант, например:
enum { Yellow=5, Cyan, Magenta};
или, если следовать правилу использования в именах констант только заглавных букв:
enum { YELLOW=5, CYAN, MAGENTA};
Здесь после первого элемента стоит знак "=" и за ним число, это число определяет, с какого значения идет нумерация перечисленных констант (следующая константа будет иметь значение на единицу больше). Если не указывать это начальное число, то нумерация констант будет идти от нуля. Таким образом, к перечисленным константам можно обращаться по их номерам, а можно задать и полностью свою систему обозначений:
typedef enum { START END FLAG = 0x0001, /* Event Flag 0 * / TEST END FLAG = 0x0002, /* Event Flag 1 * / SYS INIT END = 0x0004, /* Event Flag 2 */ CODEC CODE DOWNLOADED = 0x0008, /* Event Flag 3 */ MODEM CODE DOWNLOADED = 0x0010 /* Event Flag 4 */ } E_RUN_FLAG;
Такое определение перечислимого типа позволяет закодировать значения единицы в разрядах с нулевого по четвертый соответственно. Важно только помнить, что константы типа перечисляются ВСЕГДА в порядке возрастания их значений. И при соблюдении ранее указанных правил наименований если вы где-либо в программе встретите строку определения:
E_RUN_FLAG My_Indicator;
то вы легко догадаетесь, что переменная My_Indicator имеет перечислимый тип.
Ключевое слово void определяет отсутствие типа и используется для "нейтрализации" значения, возвращаемого функцией [9].
Сложные типы
В языке Си определены следующие механизмы для задания сложных типов:
- массивы;
- структуры;
- указатели;
- строки;
- объединения.
Массивы
Массивы представляют собой однородную последовательность элементов, каждый из которых характеризуется порядковым номером в данной последовательности. Номер элемента указывается вслед за идентификатором последовательности (идентификатором массива) в квадратных скобках: My_Array[i] , Your_Array[5] и т.п. Самый первый элемент массива имеет порядковый номер 0 (нуль).
Объявление массива в программе в простейшем случае может выглядеть так:
int My_Vector[3] ;
где константа 3 указывает, что последовательность, представляемая массивом, содержит три элемента: My_Vector [0], My_Vector [1], My Vector [2].
При этом следует помнить, что упоминание в программе самого идентификатора массива практически эквивалентно указанию адреса его нулевого элемента.
Записи
Записи (или структуры) представляют собой набор полей, объединенных вместе. Можно работать и с каждым полем отдельно, и со всеми полями, как с записью, вместе.
Вот пример задания структуры:
struct goods { char * name; long price; int volume; };
Здесь goods - имя структурного типа. В этом случае объявление переменной food такого типа будет иметь вид:
struct goods food;
Если же объявить структуру как:
typedef struct { char * name; long price; int volume; } GOODS;
то можно будет объявлять переменные, используя только имя типа:
GOODS food;
Язык Си разрешает присваивание структур (в отличие от присваивания массивов, которое может быть выполнено только поэлементным присваиванием).
При объявлении переменной структурного типа можно проинициализировать ее значение при помощи следующей конструкции:
GOODS food = {"milk", 25.6, 1} ;
Для работы с полями в языке используется составное имя с точкой:
food.price = 27.5;