union {
struct {
int type;
} n;
struct {
int type;
int intnode;
} ni;
struct {
int type;
float floatnode;
} nf;
} u;
...
u.nf.type = FLOAT;
u.nf.floatnode = 3.14;
...
if (u.n.type == FLOAT)
... sin(u.nf.floatnode) ...
A8.4. Перечисления
Перечисления - это уникальный тип, значения которого покрываются множеством именованных констант, называемых перечислителями. Вид спецификатора перечисления заимствован у структур и объединений.
спецификатор-перечисления:
enum идентификаторнеоб {список-перечислителей}
enum идентификатор
список-перечислителей:
перечислитель
список-перечислителей , перечислитель
перечислитель:
идентификатор
идентификатор = константное-выражение
Идентификаторы, входящие в список перечислителей, объявляются константами типа int и могут употребляться везде, где требуется константа. Если в этом списке нет ни одного перечислителя со знаком =, то значения констант начинаются с 0 и увеличиваются на 1 по мере чтения объявления слева направо. Перечислитель со знаком = дает соответствующему идентификатору значение; последующие идентификаторы продолжают прогрессию от заданного значения.
Имена перечислителей, используемые в одной области видимости, должны отличаться друг от друга и от имен обычных переменных, однако их значения могут и совпадать.
Роль идентификатора в переч-спецификаторе аналогична роли тега структуры в структ-спецификаторе: он является именем некоторого конкретного перечисления. Правила для списков и переч-спецификаторов (с тегами и без) те же, что и для спецификаторов структур или объединений, с той лишь оговоркой, что элементы перечислений не бывают незавершенного типа; тег переч-спецификатора без списка перечислителей должен иметь в пределах области видимости спецификатор со списком.
В первой версии языка перечислений не было, но они уже несколько лет применяются.
А8.5. Объявители
Объявители имеют следующий синтаксис:
объявитель:
указательнеоб собственно-объявитель
собственно-объявитель:
идентификатор
(объявитель)
собственно-объявитель [константное-выражениенеоб]
собственно-объявитель (список-типов-параметров)
собственно-объявитель (список-идентификаторовнеоб)
указатель:
* список-квалификаторов-типанеоб
* список-квалификаторов-типанеоб указатель
список-квалификаторов-типа:
квалификатор-типа
список-квалификаторов-типа квалификатор-типа
У структуры объявителя много сходных черт со структурой подвыражений, поскольку в объявителе, как и в подвыражении, допускаются операции косвенного обращения, обращения к функции и получения элемента массива (с тем же порядком применения).
A8.6. Что означают объявители
Список объявителей располагается сразу после спецификаторов типа и указателя класса памяти. Главный элемент любого объявителя - это объявляемый им идентификатор; в простейшем случае объявитель из него одного и состоит, что отражено в первой строке продукции грамматики с именем собственно- объявитель. Спецификаторы класса памяти относятся непосредственно к идентификатору, а его тип зависит от вида объявителя. Объявитель следует воспринимать как утверждение: если в выражении идентификатор появляется в том же контексте, что и в объявителе, то он обозначает объект специфицируемого типа.
Если соединить спецификаторы объявления, относящиеся к типу (A8.2), и некоторый конкретный объявитель, то объявление примет вид "T D", где T - тип, a D - объявитель. Эта запись индуктивно придает тип идентификатору любого объявителя.
В объявлении T D, где D - просто идентификатор, тип идентификатора есть T.
В объявлении T D, где D имеет вид
( D1 )
тип идентификатора в D1 тот же, что и в D. Скобки не изменяют тип, но могут повлиять на результаты его "привязки" к идентификаторам в сложных объявителях.
A8.6.1. Объявители указателей
В объявления T D, где D имеет вид
* список-квалификаторов-типанеоб D1
а тип идентификатора объявления T D1 есть "модификатор-типа T", тип идентификатора D есть "модификатор-типа список-квалификаторов-типа указатель на T". Квалификаторы, следующие за *, относятся к самому указателю, а не к объекту, на который он указывает. Рассмотрим, например, объявление
int *ap[];
Здесь ap[] играет роль D1; объявление int ap[] следует расшифровать (см. ниже) как "массив из int": список квалификаторов типа здесь пуст, а модификатор типа есть "массив из". Следовательно, на самом деле объявление ap гласит: "массив из указателей на int". Вот еще примеры объявлений:
int i, *pi, *const cpi = &i;
const int ci = 3, *pci;
В них объявляются целое i и указатель на целое pi. Значение указателя cpi неизменно; cpi всегда будет указывать в одно и то же место, даже если значение, на которое он указывает, станет иным. Целое ci есть константа, оно измениться не может (хотя может инициализироваться, как в данном случае). Тип указателя pci произносится как "указатель на const int"; сам указатель можно изменить; при этом он будет указывать на другое место, но значение, на которое он будет указывать, с помощью pci изменить нельзя.