int far* pascal function();
9.2. Перечислимый тип данных Объявление переменной перечислимого типа задает имя переменной и определяет список именованных констант, значения которых она может принимать. Каждому элементу списка перечисления ставится в соответствие целое число. Переменная перечислимого типа может принимать только значения из своего списка перечисления. Практически в любом контексте перечислимый тип интерпретируется как int; первый элемент списка перечисления по умолчанию равен 0.В примере ниже описывается тип day для перечисления дней недели. При описании переменной типа сразу же создается переменная workday.enum day { SATURDAY, SUNDAY=0,MONDAY,
TUESDAY, WEDNESDAY, THURSDAY, FRIDAY }
workday;
workday = WEDNESDAY; //SATURDAY также =0!
В следующем примере значения переменной перечислимого типа последовательно распечатываются как целые.
typedef enum season { spring, summer, autumn, winter };season now=spring;for (int i=0; i<4; i++) printf ("\n%d", now++); //0,1,2,3В последнем примере значение item3 установлено равным 0, однако при увеличении переменной myitem в цикле она последовательно примет значения от 0 до 3.#include <stdio.h>
|
|
typedef enum item {
item1, item2, item3=0, item4 };
void main () {
item myitem=item1;
for (int i=0; i<4; i++)
printf ("\n%d",myitem++); //0,1,2,3
myitem=item1; printf ("\n%d",myitem); //0
myitem=item2; printf ("\n%d",myitem); //1
myitem=item3; printf ("\n%d",myitem); //0
myitem=item4; printf ("\n%d",myitem); //1
}
9.3. СтруктурыСтруктура — основной составной тип данных. В отличие от массива, она объединяет в одном объекте совокупность значений, которые могут иметь различные типы.
В Си реализован ограниченный набор операций над структурами как единым целым: передача структуры в качестве аргумента функции, возврат структуры из функции, получение ее адреса и создание указателя на структуру. Можно присваивать одну структуру другой, если они имеют одинаковый тег (структурный тип).
Общий синтаксис описания структуры следующий:
struct тег{
список объявлений элементов;
} список описателей;
Например, классический способ определения структурного типа может выглядеть так:
struct book {
char title [80];
char author [40];
float cost;
};
struct book mybook;
Рекомендуется в описании структуры использовать ключевое слово typedef:
typedef struct point {
double x,y;
};
В этом случае можно не писать ключевое слово struct в описании структур вновь созданного типа или при передаче их функциям. Обращение к полю структуры выполняется с помощью первичной операции "." (точка).
void main () {
point a,b;
a.x=a.y=0;
b=a;
printf ("\na=(%lf,%lf)",a.x,a.y);
printf ("\nb=(%lf,%lf)",b.x,b.y);
}
Альтернативный вид программы мог бы быть следующим:
struct point {
//'typedef' здесь был бы ошибкой!
double x,y;
} a,b;
void main () {
a.x=a.y=0;
b=a;
//...
}
Элемент структуры не может быть структурой того же типа, в которой он содержится. Однако он может быть объявлен как указатель на тип структуры, в которую он входит. Это позволяет создавать связанные списки структур.
|
|
9.4. Битовые поля структур используются обычно в двух целях:
· для экономии памяти, поскольку позволяют плотно упаковать значения не по границам байтов;
· для организации удобного доступа к регистрам внешних устройств, в которых различные биты могут иметь самостоятельное функциональное назначение, например, при доступе к элементам файловых таблиц FAT.
Объявление битового поля имеет следующий синтаксис:
типидентификатор: константное_выражение;
Целочисленное константное выражение, записанное после двоеточия, определяет число бит, выделяемых под переменную.
|
|
Идентификатор необязателен. Неименованное битовое поле означает пропуск указанного числа битов перед размещением следующего элемента структуры. Неименованное битовое поле, для которого указан размер 0, имеет специальное назначение: оно гарантирует, что память для следующей переменной в этой структуре будет начинаться на границе машинного слова (int). Это относится и к следующему битовому полю.
Битовое поле не может выходить за границу ячейки объявленного для него типа. Например, битовое поле, unsigned int, либо упаковывается в пространство, оставшееся в текущей двухбайтовой ячейке от размещения предыдущего битового поля, либо, если предыдущий элемент структуры не был битовым полем или памяти в текущей ячейке недостаточно, в новую ячейку unsigned int.
В примере ниже показана структура, описывающая текстовый экран консоли с возможностью доступа к отдельным битам байта‑атрибута через поля.
struct {
unsigned background: 8;
unsigned color: 4;
unsigned underline: 1;
unsigned blink: 1;
} screen [25][80];
9.5. Объединение позволяет в разные моменты времени хранить в одном объекте значения различного типа. При объявлении объединения для него описывается набор типов значений, которые могут с ним ассоциироваться. В каждый момент времени объединение интерпретируется как значение только одного типа из набора. Контроль над тем, какого типа значение хранится в данный момент в объединении, возлагается на программиста. Синтаксис объявления объединения имеет следующий вид:
union тег {
список_объявлений_элементов;
} список_описателей;
Память, которая выделяется для объединения, определяется размером наиболее длинного из его элементов. Все элементы объединения размещаются с одного и того же адреса памяти. Значение текущего элемента объединения теряется, когда другому элементу присваивается значение. В качестве примера приведем объединение, которое можно интерпретировать как знаковое или беззнаковое целое число.
union sign {
int svar;
unsigned uvar;
|
|
} number;
sign number2;
Во втором примере показано объединение, которое можно использовать для получения либо полного двухбайтового кода нажатой клавиши, либо отдельно скан‑ и ASCII‑кодов.
union key {
char k[2];
unsigned kod;
};
Элементами объединений могут быть и указатели. Например, в приведенном далее коде с помощью 4‑байтового указателя "сегмент‑смещение" отслеживается нажатие клавиш Ctrl, Shift или Alt через BIOS.
#include <stdio.h>#include <conio.h>struct FAR_PTR { unsigned off, seg;};union MK_FAR { unsigned char far *ptr; struct FAR_PTR mk;} work;void main () { work.mk.off = 0x17; work.mk.seg = 0x40; //сегмент и смещение в BIOS, //где хранится флаг нажатия клавиш while (!kbhit ()) { int shift = *(work.ptr); cprintf ("\r%02d",shift); }}