Керниган и Ритчи - Язык программирования Си (793773), страница 53
Текст из файла (страница 53)
Если список типов параметровзаканчивается многоточием ", ...", то функция может иметь больше аргументов, чем число явноописанных параметров. (См. А7.3.2.)Типы параметров, являющихся массивами и функциями, заменяются на указатели в соответствии с правиламипреобразования параметров (А10.1).
Единственный спецификатор класса памяти, который разрешаетсяиспользовать в объявлении параметра, — это register, однако он игнорируется, если объявитель функциине является заголовком ее определения. Аналогично, если объявители в объявлениях параметров содержатидентификаторы, а объявитель функции не является заголовком определения функции, то этиидентификаторы тотчас же выводятся из текущей области видимости.При старом способе объявление функции Т D, где D имеет видD1 ( список-идентификаторовнеоб )и тип идентификатора объявления Т D1 есть "модификатор-типа Т", тип идентификатора в D есть"модификатор-типа функция от неспецифицированных аргументов, возвращающая Т".Параметры, если они есть, имеют следующий вид:список-идентификаторов:идентификаторсписок-идентификаторов , идентификаторПри старом способе, если объявитель функции не используется в качестве заголовка определения функции(А10.1), список идентификаторов должен отсутствовать.
Никакой информации о типах параметров вобъявлениях не содержится.Например, объявлениеint f(), *fpi(), (*pfi)();объявляет функцию f, возвращающую число типа int, функцию fpi, возвращающую указатель на числотипа int, и указатель pfi на функцию, возвращающую число типа int. Ни для одной функции в объявлениине указаны типы параметров; все функции описаны старым способом.Вот как выглядит объявление в новой записи:int strcpy(char *dest, const char *source), rand(void);Здесь strcpy — функция с двумя аргументами, возвращающая значение типа int; первый аргумент —указатель на значение типа char, а второй — указатель на неизменяющееся значение типа char. Именапараметров играют роль хороших комментариев.
Вторая функция, rand, аргументов не имеет и возвращаетint.Объявители функций с прототипами параметров — наиболее важное нововведение ANSI-стандарта. Всравнении со старым способом, принятым в первой редакции языка, они позволяют проверять иприводить к нужному типу аргументы во всех вызовах. Следует однако отметить, что их введениепривнесло в язык некоторую сумятицу и необходимость согласования обеих форм. Чтобы обеспечитьсовместимость, потребовались некоторые "синтаксические уродства", а именно void, для явногоуказания на отсутствие параметров.Многоточие ", ..." применительно к функциям с варьируемым числом аргументов — такженовинка, которая вместе со стандартным заголовочным файлом макросов <stdarg.h> формализуетнеофициально используемый, но официально запрещенный в первой редакции механизм.Указанные способы записи заимствованы из языка Си++.А 8.7.
ИнициализацияС помощью иниц-объявителя можно указать начальное значение объявляемого объекта. Инициализатору,представляющему собой выражение или список инициализаторов, заключенный в фигурные скобки,предшествует знак =. Этот список может завершаться запятой; ее назначение — сделать форматированиеболее четким.инициализатор:выражение-присваивания{ список-инициализаторов }{ список-инициализаторов , }список-инициализаторов:инициализаторсписок-инициализаторов, инициализаторВ инициализаторе статического объекта или массива все выражения должны быть константными (А7.19). Еслиинициализатор auto- и register-объекта или массива находится в списке, заключенном в фигурныескобки, то входящие в него выражения также должны быть константными. Однако в случае автоматическогообъекта с одним выражением инициализатор не обязан быть константным выражением, он просто должениметь соответствующий объекту тип.В первой редакции не разрешалась инициализация автоматических структур, объединений и массивов.
ANSIстандарт позволяет это; однако, если инициализатор не может быть представлен одним простымвыражением, инициализация может быть выполнена только с помощью константных конструкций.Статический объект, инициализация которого явно не указана, инициализируется так, как если бы ему (илиего элементам) присваивалась константа 0. Начальное значение автоматического объекта, явным образом неинициализированного, не определено.Инициализатор указателя или объекта арифметического типа — это одно выражение (возможно,заключенное в фигурные скобки), которое присваивается объекту.Инициализатор структуры — это либо выражение того же структурного типа, либо заключенные в фигурныескобки инициализаторы ее элементов, заданные по порядку. Безымянные битовые поля игнорируются и неинициализируются.
Если инициализаторов в списке меньше, чем элементов, то оставшиеся элементыинициализируются нулем. Инициализаторов не должно быть больше числа элементов.Инициализатор массива — это список инициализаторов его элементов, заключенный в фигурные скобки. Еслиразмер массива не известен, то он считается равным числу инициализаторов, при этом тип его становитсязавершенным. Если размер массива известен, то число инициализаторов не должно превышать числа егоэлементов; если инициализаторов меньше, оставшиеся элементы обнуляются.Как особый выделен случай инициализации массива символов.
Последний можно инициализировать спомощью строкового литерала; символы инициализируют элементы массива в том порядке, как они заданы встроковом литерале. Точно так же, с помощью литерала из расширенного набора символов (А2.6), можноинициализировать массив типа wchar_t. Если размер массива не известен, то он определяется числомсимволов в строке, включая и завершающий NULL-символ; если размер массива известен, то число символовв строке, не считая завершающего NULL-символа, не должно превышать его размера.Инициализатором объединения может быть либо выражение того же типа, либо заключенный в фигурныескобки инициализатор его первого элемента.В первой версии языка не позволялось инициализировать объединения.
Правило "первого элемента"не отличается изяществом, однако не требует нового синтаксиса. Стандарт ANSI проясняет еще исемантику не инициализируемых явно объединений.Введем для структуры и массива обобщенное имя: агрегат. Если агрегат содержит элементы агрегатноготипа, то правила инициализации применяются рекурсивно. Фигурные скобки в некоторых случаяхинициализации можно опускать.
Если инициализатор элемента агрегата, который сам является агрегатом,начинается с левой фигурной скобки, то этот подагрегат инициализируется последующим спискомразделенных запятыми инициализаторов; считается ошибкой, если количество инициализаторов подагрегатапревышает число его элементов. Если, однако, инициализатор подагрегата не начинается с левой фигурнойскобки, то чтобы его инициализировать, нужно отсчитать соответствующее число элементов из списка; приэтом остальные элементы инициализируются следующими инициализаторами агрегата, для которого данныйподагрегат является частью.Напримерint х[] = { 1, 3, 5 };объявляет и инициализирует х как одномерный массив с тремя элементами, поскольку размер не был указан,а список состоит из трех инициализаторов.float{{{};y[4][3]1, 3, 52, 4, 63, 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};Инициализатор для у начинается с левой фигурной скобки, но для у[0] скобки нет, поэтому из списка будутвзяты три элемента. Аналогично по три элемента будут взяты для y[1], а затем и для y[2]. Вfloat y[4][3] = {{ 1 }, { 2 }, { 3 }, { 4 }};инициализируется первый столбец матрицы у, все же другие элементы остаются нулевыми.Наконец,char msg[] = "Синтаксическая ошибка в строке %s\n";представляет собой пример массива символов, элементы которого инициализируются с помощью строки; вего размере учитывается и завершающий NULL-символ.А 8.8.
Имена типовВ ряде случаев возникает потребность в применении имени типа данных (например, при явном приведении ктипу, в указании типов параметров внутри объявлений функций, в аргументе оператора sizeof). Этапотребность реализуется с помощью имени типа, определение которого синтактически почти совпадает собъявлением объекта того же типа. Оно отличается от объявления лишь тем, что не содержит имени объекта.имя-типа:список-спецификаторов-квалификаторов абстрактный-объявительнеобабстрактный-объявитель:указательуказательнеоб собственно-абстрактный-объявительсобственно-абстрактный-объявитель:( абстрактный-объявитель )собственно-абстрактный-объявительнеоб [ константное-выражениенеоб ]собственно-абстрактный-объявительнеоб ( список-типов-параметровнеоб )Можно указать одно-единственное место в абстрактном объявителе, где мог бы оказаться идентификатор,если бы данная конструкция была полноценным объявителем.
Именованный тип совпадает с типом этого"невидимого идентификатора". Напримерintint *intintintint*[3](*)[]*()(*[])(void)соответственно обозначают типы int, "указатель на int", "массив из трех указателей наint", "указатель на массив из неизвестного количества int", "функция неизвестногоколичества параметров, возвращающая указатель на int", "массив неизвестногоколичества указателей на функции без параметров, каждая из которых возвращаетint".А 8.9. Объявление typedefОбъявления, в которых спецификатор класса памяти есть typedef, не объявляют объектов — ониопределяют идентификаторы, представляющие собой имена типов.
Эти идентификаторы называютсяtypedef-именами.typedef-имя:идентификаторОбъявление typedef приписывает тип каждому имени своего объявителя обычным способом (см. А8.6.). Сэтого момента typedef-имя синтаксически эквивалентно ключевому слову спецификатора типа,обозначающему связанный с ним тип. Например, послеtypedef long Blockno, *Blockptr;typedef struct { double r, theta; } Complex;допустимы следующие объявления:Blockno b;extern Blockptr bp;Complex z, *zp;b принадлежит типу long, bp — типу "указатель на long", z — это структура заданного вида, a zp —принадлежит типу "указатель на такую структуру".Объявление typedef не вводит новых типов, оно только дает имена типам, которые могли бы бытьспецифицированы и другим способом.














