Главная страница
Навигация по странице:

  • А 8.9. Объявление typedef

  • А 8.10. Эквивалентность типов

  • А 9.1. Помеченные инструкции

  • А 9.2. Инструкция-выражение

  • А 9.3. Составная инструкция

  • А 9.4. Инструкции выбора

  • А 9.5. Циклические инструкции

  • А 9.6. Инструкции перехода

  • А 10. Внешние объявления

  • Язык программирования Си Брайан Керниган, Деннис Ритчи 3е издание Версия 1 Table of Contents


    Скачать 2.33 Mb.
    НазваниеЯзык программирования Си Брайан Керниган, Деннис Ритчи 3е издание Версия 1 Table of Contents
    Дата18.09.2022
    Размер2.33 Mb.
    Формат файлаpdf
    Имя файлаBrian_Kernighan_Dennis_Ritchie-The_C_Programming_Language-RU.pdf
    ТипДокументы
    #683263
    страница26 из 31
    1   ...   23   24   25   26   27   28   29   30   31
    А 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, 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
    };
    Инициализатор для у начинается с левой фигурной скобки, но для у[0]
    скобки нет, поэтому из списка будут взяты три элемента. Аналогично по три элемента будут взяты для y[1]
    , а затем и для y[2]
    . В float y[4][3] = {
    { 1 }, { 2 }, { 3 }, { 4 }
    }; инициализируется первый столбец матрицы у, все же другие элементы остаются нулевыми.
    Наконец, char msg[] = "Синтаксическая ошибка в строке %s\n"; представляет собой пример массива символов, элементы которого инициализируются с помощью строки; в его размере учитывается и завершающий
    NULL
    -символ.
    А 8.8. Имена типов
    В ряде случаев возникает потребность в применении имени типа данных (например, при явном приведении к типу, в указании типов параметров внутри объявлений функций, в аргументе оператора sizeof
    ). Эта потребность реализуется с помощью имени типа, определение которого синтактически почти совпадает с объявлением объекта того же типа. Оно отличается от объявления лишь тем, что не содержит имени объекта.
    имя-типа:
    список-спецификаторов-квалификаторов абстрактный-объявитель
    необ
    абстрактный-объявитель:
    указатель
    указатель
    необ
    собственно-абстрактный-объявитель
    собственно-абстрактный-объявитель:
    ( абстрактный-объявитель )
    собственно-абстрактный-объявитель
    необ
    [ константное-выражение
    необ
    ]
    собственно-абстрактный-объявитель
    необ
    ( список-типов-параметров
    необ
    )
    Можно указать одно-единственное место в абстрактном объявителе, где мог бы оказаться идентификатор, если бы данная конструкция была полноценным объявителем. Именованный тип совпадает с типом этого "невидимого идентификатора". Например int int *
    int *[3] int (*)[] int *() int (*[])(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 не вводит новых типов, оно только дает имена типам, которые могли бы быть специфицированы и другим способом. Например, b
    имеет тот же тип, что и любой другой объект типа long typedef
    -имена могут быть перекрыты другими определениями во внутренней области видимости, но при условии, что в них присутствует указание типа. Например extern Blockno; не переобъявляет
    Blockno
    , а вот extern int Blockno; переобъявляет.
    А 8.10. Эквивалентность типов
    Два списка спецификаторов типа эквивалентны, если они содержат одинаковый набор спецификаторов типа с учетом синонимичности названий (например, long и long int считаются одинаковыми типами).
    Структуры, объединения и перечисления с разными тегами считаются разными, а каждое безтеговое объединение, структура или перечисление представляет собой уникальный тип.

    Два типа считаются совпадающими, если их абстрактные объявители (А8.8) после замены всех typedef
    - имен их типами и выбрасывания имен параметров функций составят эквивалентные списки спецификаторов типов. При сравнении учитываются размеры массивов и типы параметров функций.
    А 9. Инструкции
    За исключением оговоренных случаев инструкции выполняются в том порядке, как они написаны. Инструкции не имеют значений и выполняются, чтобы произвести определенные действия. Все виды инструкций можно разбить на несколько групп:
    инструкция:
    помеченная-инструкция
    инструкция–выражение
    составная-инструкция
    инструкция-выбора
    циклическая-инструкция
    инструкция-перехода
    А 9.1. Помеченные инструкции
    Инструкции может предшествовать метка.
    помеченная-инструкция:
    идентификатор : инструкция case константное-выражение : инструкция default : инструкция
    Метка, состоящая из идентификатора, одновременно служит и объявлением этого идентификатора.
    Единственное назначение идентификатора метки — указать место перехода для goto
    . Областью видимости идентификатора-метки является текущая функция. Так как метки имеют свое собственное пространство имен, они не "конфликтуют" с другими идентификаторами и не могут быть перекрыты (см. А11.1.). case
    -метки и default
    -метки используются в инструкции switch
    (A9.4). Константное выражение в case должно быть целочисленным.
    Сами по себе метки не изменяют порядка вычислений.
    А 9.2. Инструкция-выражение
    Наиболее употребительный вид инструкции — это инструкция-выражение.
    инструкция-выражение:
    выражение
    необ
    ;
    Чаще всего инструкция-выражение — это присваивание или вызов функции. Все действия, реализующие побочный эффект выражения, завершаются, прежде чем начинает выполняться следующая инструкция. Если выражение в инструкции опущено, то она называется пустой; пустая инструкция часто используется для обозначения пустого тела циклической инструкции или в качестве места для метки.
    А 9.3. Составная инструкция
    Так как в местах, где по синтаксису полагается одна инструкция, иногда возникает необходимость выполнить несколько, предусматривается возможность задания составной инструкции (которую также называют блоком). Тело определения функции есть составная инструкция:
    составная-инструкция:
    { список-объявлений список-инструкций
    необ
    }
    список-объявлений:

    объявление
    список-объявлений объявление
    список-инструкций:
    инструкция
    список-инструкций инструкция
    Если идентификатор из списка объявлений находился в области видимости объемлющего блока, то действие внешнего объявления при входе внутрь данного блока приостанавливается (А11.1), а после выхода из него возобновляется. Внутри блока идентификатор может быть объявлен только один раз. Для каждого отдельного пространства имен эти правила действуют независимо (А11); идентификаторы из разных пространств имен всегда различны.
    Инициализация автоматических объектов осуществляется при каждом входе в блок и продолжается по мере продвижения по объявителям. При передаче управления внутрь блока никакие инициализации не выполняются. Инициализации статических объектов осуществляются только один раз перед запуском программы.
    А 9.4. Инструкции выбора
    Инструкции выбора осуществляют отбор одной из нескольких альтернатив, определяющих порядок выполнения инструкций.
    инструкция-выбора: if ( выражение ) инструкция if ( выражение ) инструкция else инструкция switch ( выражение ) инструкция
    Оба вида if
    -инструкций содержат выражение, которое должно иметь арифметический тип или тип указателя. Сначала вычисляется выражение со всеми его побочными эффектами, результат сравнивается с 0.
    В случае несовпадения с 0 выполняется первая подинструкция. В случае совпадения с 0 для второго типа if выполняется вторая подинструкция. Связанная со словом else неоднозначность разрешается тем, что слово else соотносят с последней еще не имеющей else if
    -инструкцией, расположенной в одном с этим else блоке и на одном уровне вложенности блоков.
    Инструкция switch вызывает передачу управления на одну из нескольких инструкций в зависимости от значения выражения, которое должно иметь целочисленный тип.
    Управляемая с помощью switch подинструкция обычно составная. Любая инструкция внутри этой подинструкции может быть помечена одной или несколькими case
    -метками (А9.1). Управляющее выражение подвергается целочисленному повышению (А6.1), а case
    -константы приводятся к повышенному типу. После такого преобразования никакие две case
    -константы в одной инструкции switch не должны иметь одинаковых значений. Со switch
    -инструкцией может быть связано не более одной default
    -метки.
    Конструкции switch допускается вкладывать друг в друга; case и default
    -метки относятся к самой внутренней switch
    -инструкции из тех, которые их содержат.
    Инструкция switch выполняется следующим образом. Вычисляется выражение со всеми побочными эффектами, и результат сравнивается с каждой case
    -константой. Если одна из case
    -констант равна значению выражения, управление переходит на инструкцию с соответствующей case
    -меткой. Если ни с одной из case
    -констант нет совпадения, управление передается на инструкцию с default
    -меткой, если такая имеется, в противном случае ни одна из подинструкций switch не выполняется.
    В первой версии языка требовалось, чтобы выражение и case
    -константы в switch были типа int

    А 9.5. Циклические инструкции
    Циклические инструкции специфицируют циклы.
    циклическая-инструкция: while ( выражение ) инструкция do инструкция while ( выражение ) for ( выражение
    необ
    ; выражение
    необ
    ; выражение
    необ
    ) инструкция
    В инструкциях while и do выполнение подинструкций повторяется до тех пор, пока значение выражения не станет нулем. Выражение должно иметь арифметический тип или тип указателя. В while вычисление выражения со всеми побочными эффектами и проверка осуществляются перед каждым выполнением инструкции, а в do
    — после.
    В инструкции for первое выражение вычисляется один раз, тем самым осуществляется инициализация цикла. На тип этого выражения никакие ограничения не накладываются. Второе выражение должно иметь арифметический тип или тип указателя; оно вычисляется перед каждой итерацией. Как только его значение становится равным 0, for прекращает свою работу. Третье выражение вычисляется после каждой итерации и, следовательно, выполняет повторную инициализацию цикла. Никаких ограничений на его тип нет.
    Побочные эффекты всех трех выражений заканчиваются по завершении их вычислений. Если подинструкция не содержит в себе continue
    , то for ( выражение1 ; выражение2 ; выражение3 ) инструкция эквивалентно конструкции
    выражение1; while ( выражение2 ) {
    инструкция
    выражение3;
    }
    Любое из трех выражений цикла может быть опущено. Считается, что отсутствие второго выражения равносильно сравнению с нулем ненулевой константы.
    А 9.6. Инструкции перехода
    Инструкции перехода осуществляют безусловную передачу управления.
    инструкция-перехода: goto идентификатор ; continue ; break ; return выражение
    необ
    ;
    В goto
    -инструкции идентификатор должен быть меткой (А9.1), расположенной в текущей функции.
    Управление передается на помеченную инструкцию.
    Инструкцию continue можно располагать только внутри цикла. Она вызывает переход к следующей итерации самого внутреннего содержащего ее цикла. Говоря более точно, для каждой из конструкций while ( ... ) { contin: ;
    } do { contin: ; while ( ... ) ; for ( ... ) { contin: ;
    }
    инструкция continue
    , если она не помещена в еще более внутренний цикл, делает то же самое, что и goto contin
    Инструкция break встречается в циклической или в switch
    -инструкции, и только в них. Она завершает работу самой внутренней циклической или switch
    -инструкции, содержащей данную инструкцию break
    , после чего управление переходит к следующей инструкции.
    С помощью return функция возвращает управление в программу, откуда была вызвана. Если за return следует выражение, то его значение возвращается вызвавшей эту функцию программе. Значение выражения приводится к типу так, как если бы оно присваивалось переменной, имеющей тот же тип, что и функция.
    Ситуация, когда "путь" вычислений приводит в конец функции (т. е. на последнюю закрывающую фигурную скобку), равносильна выполнению return
    -инструкции без выражения. При этом, а также в случае явного задания return без выражения возвращаемое значение не определено.
    А 10. Внешние объявления
    То, что подготовлено в качестве ввода для Си-компилятора, называется единицей трансляции. Она состоит из последовательности внешних объявлений, каждое из которых представляет собой либо объявление, либо определение функции.
    единица-трансляции:
    внешнее-объявление
    единица-трансляции внешнее-объявление
    внешнее-объявление:
    определение-функции
    объявление
    Область видимости внешних объявлений простирается до конца единицы трансляции, в которой они объявлены, точно так же, как область видимости объявлений в блоке распространяется до конца этого блока.
    Синтаксис внешнего объявления не отличается от синтаксиса любого другого объявления за одним исключением: код функции можно определять только с помощью внешнего объявления.
    1   ...   23   24   25   26   27   28   29   30   31


    написать администратору сайта