Перечислимый тип
Перечислимый тип данных аналогичен скалярным типамязыка Паскаль. Спецификатор перечислимого типа имеет следу-ющий вид: спецификатор _ перечисления: enum список _ перечисления enum идентификатор список _ перечисления enum идентификатор список _ перечисления: перечисляемое список _ перечисления, перечисляемое перечисляемое: идентификатор идентификатор = константное выражение -29- Роль идентификатора в спецификаторе _ перечисления пол-ностью аналогична роли ярлыка структуры в спецификаторе _ структуры; идентификатор обозначает определен-ное перечисление. Например, описание enum color {red, white, black, blue };... enum color *cp, col; объявляет идентификатор color ярлыком перечисления типа,описывающего различные цвета и затем объявляет cр указателемна объект этого типа, а col - объектом этого типа. Идентификаторы в списке _ перечисления становятся конс-тантами и могут появляться там, где требуются (по контексту)константы. Если не используется вторая форма перечисляемого(с равенством =), то величины констант начинаются с 0 и воз-растают на 1 в соответствии с прочтением их описания слеванаправо. Перечисляемое с присвоением = придает соответствую-щему идентификатору указанную величину; последующие иденти-фикаторы продолжают прогрессию от приписанной величины. Ярлыки перечислений и имена констант должны быть раз-личными и не совпадать с именами ярлыков и членов структур. Объекты данного типа перечисления рассматриваются какобъекты, имеющие тип, отличный от любых типов и контролирую-щая программа lint сообщает об ошибках несоответствия типов.В реализации на CM_ЭВМ со всеми перечисляемыми переменнымиоперируют так, как если бы они имели тип int.Инициализация
Описатель может указывать начальное значение описывае-мого идентификатора. Инициализатор состоит из выражения илизаключенного в фигурные скобки списка значений, перед кото-рыми ставится знак =. инициализатор: = выражение = {список_иниц} = {список _ иниц, } список _ иниц: выражение список _ иниц, список _ иниц {список _ иниц} где список _ иниц - список _ инициализаторов -30- Все выражения, входящие в инициализатор статической иливнешней переменной, должны быть либо константными выражени-ями, либо выражениями, которые сводятся к адресу ранее опи-санной переменной, смещенному на константное (возможно,нулевое) выражение. Автоматические и регистровые переменныемогут быть инициализированы произвольными выражениями, вклю-чающими константы и ранее описанные переменные и функции. Гарантируется, что неинициализированные статические ивнешние переменные получают в качестве начальных значений 0;неинициализированные автоматические и регистровые переменныев качестве начальных значений содержат мусор. Когда инициализатор применяется к скаляру (указателюили объекту арифметического типа), то он состоит из одноговыражения, возможно заключенного в фигурные скобки. Началь-ное значение объекта находится из выражения; выполняются теже самые преобразования, что и при присваивании. Когда описываемая переменная является агрегатом (струк-турой или массивом), то инициализатор состоит из заключен-ного в фигурные скобки и разделенного запятыми списка иници-ализаторов для членов агрегата. Этот список составляется впорядке возрастания индекса или в соответствии с порядкомчленов. Если агрегат содержит подагрегаты, то это правилоприменяется рекурсивно к членам агрегата. Если количествоинициализаторов в списке оказывается меньше числа членовагрегата, то оставшиеся члены агрегата заполняются нулями.Запрещается инициализировать объединения или автоматическиеагрегаты. Фигурные скобки могут интерпретироваться следующимобразом. Если инициализатор начинается с левой фигурнойскобки, то последующий разделенный запятыми список инициали-заторов инициализирует члены агрегата; будет ошибкой, если всписке окажется больше инициализаторов, чем членов агрегата.Если однако инициализатор не начинается с левой фигурнойскобки, то из списка берется только нужное для членов дан-ного агрегата число элементов; оставшиеся элементы использу-ются для инициализации следующего члена агрегата, частьюкоторого является настоящий агрегат. Следовательно, скобки внекоторых случаях можно опускать. Последнее сокращение допускает возможность инициализа-ции массива типа char с помощью строки. В этом случае членымассива последовательно инициализируются символами строки. Например, int х [] = { 1,3,5 }; описывает и инициализирует х как одномерный массив; пос-кольку размер массива не специфицирован, а список -31- инициализатора содержит три элемента, считается, что массивсостоит из трех членов. Вот пример инициализации с полным использованием фигур-ных скобок: float *y[4][3] = { (1, 3, 5), (2, 4, 6), (3, 5, 7), }; Здесь 1, 3 и 5 инициализируют первую строку массива y [0], аименно y [0][0], y [0][1] и y [0][2]. Аналогичным образом сле-дующие две строчки инициализируют y [1] и y [2]. Инициализаторзаканчивается преждевременно, и, следовательно, массив y [3]инициализируется нулями. В точности такого же эффекта можнобыло бы достичь, написав float y [ 4 ][ 3 ] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; Инициализатор для y начинается с левой фигурной скобки, ноинициализатора для y [0] нет. Поэтому используется 3 элементаиз списка. Аналогично следующие три элемента используютсяпоследовательно для y [1] и y [2]. Следующее описание float y [4][3] = { {1}, {2}, {3}, {4} }; инициализирует первый столбец y (если его рассматривать какдвумерный массив), а остальные элементы заполняются нулями. И наконец, описание char msg [] = " syntax error on line %s\n "; демонстрирует инициализацию элементов символьного массива спомощью строки.Имена типов
В двух случаях (для явного указания типа преобразованияв конструкции перевода и для аргументов операции sizeof)желательно иметь возможность задавать тип данных. Это осу-ществляется с помощью "имени типа", которое по существуявляется описанием объекта такого типа, в котором опущеноимя самого объекта. -32- Имя типа: спецификатор _ типа абстрактный _ описатель абстрактный _ описатель: пусто (абстрактный _ описатель) *абстрактный описатель абстрактный _ описатель () абстрактный _ описатель [ констант - ное выражение ] необ Во избежание двусмысленности в конструкции (абстрактный _ описатель) требуется, чтобы абстрактный _ описатель был непуст. При этомограничении возможно однозначно определить то место вабстрактном_описателе, где должен появиться идентификатор,если бы эта конструкция была описателем в описании. Имено-ванный тип совпадает тогда с типом гипотетического идентифи-катора. Например, имена типов int int * int * [3] int (*)[3] int * () int (*)() именуют соответственно типы "целый", "указатель на целое","массив из трех указателей на целое", "указатель на массивиз трех целых", " функция, возвращающая указатель на целое"и "указатель на функцию, возвращающую целое".Описатель typedef
Описания, в которых " класс памяти " специфицирован как typedef, не вызывают выделения памяти. Вместо этого ониопределяют идентификаторы, которые позднее можно использо-вать так, словно они являются ключевыми словами, имеющимиосновные или производные типы. определяющее _ тип _ имя: идентификатор В пределах области действия описания со спецификатором typedef каждый идентификатор, описанный в нем, становитсясинтаксически эквивалентным ключевому слову, имеющему тоттип, который ассоциирует с идентификатором в описанном в п.0.4 смысле. Например, после описаний typedef int miles, *klicksp; typedef struct { double re, im; } complex; -33- конструкции miles distance; extern klicksp metricp; complex z, *zp; становятся законными описаниями; при этом типом distanceявляется int, типом metricp - "указатель на int ", типом z -специфицированная структура и типом zp - указатель на такуюструктуру. Спецификатор typedef не вводит каких-либо совершенноновых типов, а только определяет синонимы для типов, которыеможно было бы специфицировать и другим способом. Так в при-веденном выше примере переменная distance считается имеющейточно такой же тип, что и любой другой объект, описанный в int.* 6. ОПЕРАТОРЫ
За исключением особо оговариваемых случаев, операторывыполняются последовательно.