Skip to content
Ilya Andreev edited this page Sep 6, 2022 · 2 revisions

1. Обозначения

  • В используемых в этой статье обозначениях синтаксические нетерминалы обозначаются курсивом, а терминалы - жирным шрифтом. Двоеточие (:), следующее за нетерминалом, означает начало его определения. Альтернативные определения перечислены на отдельных строках, за исключением случаев, когда им предшествуют слова "one of". Опциональная синтаксическая конструкция обозначается подстрочным "opt", так что

    {expression ₒₚₜ }

    означает опциональное выражение в фигурных скобках.

2. Базовые концепции

2.1. Область видимости идентификаторов

2.2. Время жизни объектов

2.3. Типы

  • Смысл значения, хранимого в объекте или возвращаемого функцией, определен типом выражения. Типы подразделяются на объектные типы (типы, полностью описывающие объекты) и неполные типы (типы, описывающие объекты, но которым не хватает информации для определения их размера).
  • Объект логического типа, определяемого ключевым словом bool, может хранить значения true и false.
  • Объект символьного типа, определяемого ключевым словом char, может хранить любой символ базового набора символов.
  • Объект целочисленного типа, определяемого ключевыми словами int или long, может хранить целое число от -2147483648 до +2147483647.
  • Символьный и целочисленный типы вместе называются целочисленными типами.
  • Объект вещественного типа, определяемого ключевыми словами float или double, может хранить число с плавающей точкой от ??? до ???.
  • Целочисленные и вещественные типы вместе называются арифметическими типами.
  • Пустой тип, обозначаемый ключевым словом void обозначает пустое множество значений. Это неполный тип, который не может быть дополнен.
  • Из перечисленных выше типов можно составить любое число производных типов:
    • Тип массива описывает непрерывно размещенный непустой набор объектов конкретного объектного типа, называемым типом элемента. Тип массива характеризуется типом элемента, но не его длиной.
    • Тип структуры описывает последовательно размещенный непустой набор полей-объектов (и в некоторых случаях неполных массивов). Каждое поле именовано и имеет собственный тип.
    • Тип функции описывает функцию. Функциональный тип характеризуется типом возвращаемого значения, количеством и типами параметров.
    • Тип указателя может быть образован от любого типа, который будет называться указываемым типом. Указательный тип описывает объект, чье значение указывает на сущность указываемого типа.
  • Целочисленные и указательные типы вместе называются скалярными типами.
  • Типы массивов и структур вместе называются агрегатными типами.
  • Тип массива неизвестного размера является неполным типом. Для идентификатора этого типа такой тип может быть дополнен обозначением размера в объявлении этого идентификатора.

2.4. Представления типов

2.5. Совместимость типов

3. Преобразования типов

  • TODO

4. Лексические элементы

  • TODO

5. Выражения

  • Выражение - последовательность операторов и операндов, задающая вычисление значения, указывающая на объект или функцию, генерирующая побочный эффект или любые комбинации из вышеперечисленного.
  • Группировка операндов и операторов (то есть приоритет операторов) задаются синтаксисом. Порядок вычисления операндов определен только для операторов вызова (), логической конъюнкции &&, логической дизъюнкции ||, условного оператора ?: и оператора последовательного исполнения ,. В прочих случаях порядок вычисления операндов не определен.
  • Если во время вычисления выражения возникает исключительное состояние (например, результат математически не определен или не может быть представлен значением своего типа), поведение не определено.

5.1. Первичные выражения

  • Синтаксис

    primary-expression:
        identifier
        literal
        (expression)

  • Семантика
    • Идентификатор является первичным выражением, если он был объявлен как объект (в этом случае это lvalue) или как функция. Использование необъявленного идентификатора - нарушение синтаксиса.
    • Литерал является первичным выражением. Его тип зависит от вида и значения литерала, как было описано в разделе Литералы.
    • Выражение в круглых скобках является первичным выражением. Его тип и значение идентичны типу и значению выражению внутри скобок. Это lvalue, если выражение без скобок lvalue.

5.2. Постфиксные операторы

  • Синтаксис

    postfix-expression:
        primary-expression
        postfix-expression[expression]
        postfix-expression(argument-expression-list ₒₚₜ )
        postfix-expression.identifier
        postfix-expression->identifier
        postfix-expression++
        postfix-expression

    argument-expression-list:
        initializer
        argument-expression-list,initializer

5.2.1. Вырезка из массива

  • Ограничения
    • Первое выражение должно иметь тип массив Т, второе выражение должно иметь целочисленный тип. Результат имеет тип Т.
  • Семантика
    • Постфиксное выражение, за которым следует выражение в квадратных скобках [] - вырезка элемента массива. Если объект E1 был объявлен как массив, то запись Е1[Е2] означает элемент с индексом Е2 (отсчитывая с нуля) массива Е1.
    • Последовательные операторы вырезки обозначают элемент многомерного массива.

5.2.2. Вызов функции

  • Ограничения
    • Первое выражение должно иметь тип функция, возвращающая Т. Результат вызова имеет тип Т.
  • Семантика
    • Постфиксное выражение, за которым следует разделенный запятыми список выражений (возможно пустой) в круглых скобках () означают вызов функции. Левое выражение обозначает вызываемую функцию. Список выражений определяет аргументы функции.
    • Аргумент должен удовлетворять условиям инициализации типа соответствующему параметру, как это описано в разделе Инициализация. При подготовке к вызову функции каждому параметру присваивается значение соответствующего аргумента.

5.2.3. Выборка поля структуры

  • Ограничения
    • Первый операнд оператора . должен иметь тип структура. Второй операнд должен называть поле этой структуры.
    • Первый операнд оператора -> должен иметь тип указатель на структуру. Второй операнд должен называть поле этой структуры, на которую указывает левый операнд.
  • Семантика
    • Постфиксное выражение, за которым следует оператор ., а идентификатор называет поле структуры, обозначает поле структуры. Это lvalue, если левый операнд lvalue. Результат имеет тот же тип, который имеет поле структуры.
    • Постфиксное выражение, за которым следует оператор ->, а идентификатор называет поле структуры, на которую указывает левый операнд, обозначает поле структуры. Это lvalue. Результат имеет тот же тип, который имеет поле структуры.
    • Если E - структура, то выражение (&E)->MOS эквивалентно E.MOS.

5.2.4. Постфиксные операторы инкремента и декремента

  • Ограничения
    • Операнд постфиксных операторов инкремента или декремента должен иметь арифметический тип и быть модифицируемым lvalue.
  • Семантика
    • Результатом постфиксного оператора ++ является значение операнда. После получения результата значение операнда увеличивается на 1.
    • Результатом постфиксного оператора -- является значение операнда. После получения результата значение операнда уменьшается на 1.

5.3. Унарные операторы

  • Синтаксис

    unary-expression:
        postfix-expression
        ++unary-expression
        --unary-expression
        unary-operatorunary-expression

    unary-operator: one of
        &*-̃!

5.3.1. Префиксные операторы инкремента и декремента

  • Ограничения
    • Операнд префиксных операторов инкремента или декремента должен иметь арифметический тип и быть модифицируемым lvalue.
  • Семантика
    • Значение операнда префиксного оператора ++ увеличивается на 1. Результатом является новое значение операнда.
    • Значение операнда префиксного оператора -- уменьшается на 1. Результатом является новое значение операнда.

5.3.2. Операторы взятия адреса и косвенного обращения

  • Ограничения
    • Операнд унарного оператора & должен быть lvalue.
    • Операнд унарного оператора * должен иметь тип указатель.
  • Семантика
    • Унарный оператор & возвращает адрес своего операнда. Если операнд является результатом унарного оператора *, ни этот оператор, ни оператор & не вычисляются, и результат такой, как если бы оба были опущены, за исключением того, что ограничения на операторы все еще применяются, и результат не является lvalue. В противном случае результатом является указатель на объект, обозначенный операндом.
    • Унарный оператор * обозначает косвенное обращение (разыменование). Если операнд указывает на объект, результатом будет lvalue, обозначающее объект. Если операнд имеет тип указатель на Т, результат будет иметь тип Т. Если указателю присвоено недопустимое значение, поведение унарного оператора * не определено.

5.3.3. Унарные арифметические операторы

  • Ограничения
    • Операнд унарного оператора + должен иметь арифметический тип.
    • Операнд оператора ~ должен иметь целочисленный тип.
    • Операнд оператора ! должен иметь скалярный тип.
  • Семантика
    • Результатом унарного оператора - является значение его операнда с противоположным знаком. Тип результата совпадает с типом операнда.
    • Результатом оператора ~ является побитовое дополнение операнда (то есть каждый бит в результате устанавливается тогда и только тогда, когда соответствующий бит в операнде не установлен). Результат имеет целочисленный тип.
    • Результатом оператора логического отрицания ! является false, если значение операнда равно начальному значению соответствующего типа; true в обратном случае. Результат имеет логический тип.

5.4. Мультипликативные операторы

  • Синтаксис

    multiplicative-expression:
        unary-expression
        multiplicative-expression*unary-expression
        multiplicative-expression/unary-expression
        multiplicative-expression%unary-expression

  • Ограничения
    • Операнды операторов * и / должны иметь арифметический тип.
    • Операнды оператора % должны иметь целочисленный тип.
  • Семантика
    • Результатом оператора * является произведение операндов.
    • Результатом оператора / является частное от деления первого операнда на второй; результат оператора % - остаток. В обеих операциях, если значение второго операнда равно нулю, поведение не определено.
    • При делении целых чисел результатом оператора / является алгебраическое частное с отброшенной дробной частью.

5.5. Аддитивные операторы

  • Синтаксис

    additive-expression:
        multiplicative-expression
        additive-expression+multiplicative-expression
        additive-expression-multiplicative-expression

  • Ограничения
    • Операнды операторов + и - должны иметь арифметический тип.
  • Семантика
    • Результатом оператора + является сумма операндов.
    • Результатом оператора - является разность левого и правого операндов.

5.6. Операторы битового сдвига

  • Синтаксис

    shift-expression:
        additive-expression
        shift-expression<<additive-expression
        shift-expression>>additive-expression

  • Ограничения
    • Операнды операторов битового сдвига должны иметь целочисленный тип.
  • Семантика
    • Результатом выражения E1 << E2 является E1, сдвинутое влево на E2 бит; освобожденные биты заполняются нулями.
    • Результатом выражения E1 >> E2 является E1, сдвинутое вправо на E2 бит.

5.7. Операторы сравнения

  • Синтаксис

    relational-expression:
        shift-expression
        relational-expression< shift-expression
        relational-expression> shift-expression
        relational-expression<=shift-expression
        relational-expression>=shift-expression

  • Ограничения
    • Операнды операторов сравнения должны иметь арифметический тип.
  • Семантика
    • Каждый из операторов < ("меньше"), > ("больше"), <= ("меньше или равно") и >= ("больше или равно") выдает true, если обозначенное отношение истинно, и false, если оно ложно. Результат имеет логический тип.

5.8. Операторы равенства

  • Синтаксис

    equality-expression:
        relational-expression
        equality-expression==relational-expression
        equality-expression!=relational-expression

  • Ограничения
    • Одно из следующих условий должно выполняться:
      • Оба операнда имеют арифметический тип;
      • Оба операнда имеют совместимые типы;
      • Один из операндов имеет тип указатель, а другой является литералом null.
  • Семантика
    • Каждый из операторов == ("равно") и != ("не равно") выдает true, если обозначенное отношение истинно, и false, если оно ложно. Результат имеет логический тип.

5.9. Оператор битовой конъюнкции

  • Синтаксис

    and-expression:
        equality-expression
        and-expression&equality-expression

  • Ограничения
    • Оба операнда должны иметь целочисленный тип.
  • Семантика
    • Результат бинарного оператора & - битовая конъюнкция операндов.

5.10. Оператор битовой строгой дизъюнкции

  • Синтаксис

    xor-expression:
        and-expression
        xor-expression^and-expression

  • Ограничения
    • Оба операнда должны иметь целочисленный тип.
  • Семантика
    • Результат бинарного оператора ^ - битовая строгая дизъюнкция операндов.

5.11. Оператор битовой дизъюнкции

  • Синтаксис

    or-expression:
        xor-expression
        or-expression|xor-expression

  • Ограничения
    • Оба операнда должны иметь целочисленный тип.
  • Семантика
    • Результат бинарного оператора | - битовая дизъюнкция операндов.

5.12. Оператор логической конъюнкции

  • Синтаксис

    logical-and-expression:
        or-expression
        logical-and-expression&&or-expression

  • Ограничения
    • Оба операнда должны иметь скалярный тип.
  • Семантика
    • Оператор && выдает true, если оба операнда не равны начальному значению соответствующего типа; иначе оператор выдает false.
    • Оператор && гарантирует вычисление слева направо. Если первый операнд равен начальному значению соответствующего типа, второй операнд не вычисляется.

5.13. Оператор логической дизъюнкции

  • Синтаксис

    logical-or-expression:
        logical-and-expression
        logical-or-expression||logical-and-expression

  • Ограничения
    • Оба операнда должны иметь скалярный тип.
  • Семантика
    • Оператор || выдает true, если хотя бы один из операндов не равен начальному значению соответствующего типа; иначе оператор выдает false.
    • Оператор || гарантирует вычисление слева направо. Если первый операнд не равен начальному значению соответствующего типа, второй операнд не вычисляется.

5.14. Условный оператор

  • Синтаксис

    conditional-expression:
        logical-or-expression
        logical-or-expression?expression:conditional-expression

  • Ограничения
    • Первый операнд должен иметь скалярный тип.
    • Одно из следующих условий должно выполняться для второго и третьего операндов:
      • Оба операнда имеют арифметический тип;
      • Оба операнда имеют совместимые типы;
      • Один операнд имеет тип указатель, а другой является литералом null.
  • Семантика
    • Сначала вычисляется первый операнд. Второй операнд вычисляется только если первый операнд не равен начальному значению соответствующего типа; третий операнд вычисляется только если первый операнд равен начальному значению соответствующего типа. Результатом является значение вычисленного (второго или третьего) операнда.

5.15. Операторы присваивания

  • Синтаксис

    assignment-expression:
        conditional-expression
        unary-expressionassignment-operatorinitializer

    assignment-operator: one of
        =*=/=%=+=-=<<=>>=&=ˆ=|=

  • Ограничения
    • Первый операнд оператора присваивания должен быть модифицируемым lvalue.
  • Семантика
    • Оператор присваивания сохраняет значение в объекте, обозначенном первым операндом. Результат имеет значение и тип первого операнда после присваивания, но не является lvalue.

5.15.1. Оператор простого присваивания

  • Ограничения
    • Одно из следующих условий должно выполняться:
      • Левый операнд имеет вещественный тип, и правый операнд имеет целочисленный тип;
      • Левый операнд имеет тип указатель, и правый операнд является литералом null;
      • Операнды имеют совместимые типы.
  • Семантика
    • При простом присваивании значение правого операнда конвертируется к типу присваивания и заменяет значение, хранящееся в объекте, указанном левым операндом.

5.15.2. Оператор составного присваивания

  • Ограничения
    • Операнды оператора составного присваивания должны удовлетворять требованиям соответствующего бинарного оператора
  • Семантика
    • Составное присваивание вида E1 op= E2 отличается от простого присваивания E1 = E1 op E2 только тем, что E1 вычисляется только один раз.

5.16. Оператор последовательного вычисления

  • Синтаксис

    expression:
        assignment-expression
        expression,assignment-expression

  • Семантика
    • Сначала вычисляется левый операнд; его результат отбрасывается. Затем вычисляется правый операнд; результат имеет его тип и значение.

6. Константные выражения

  • Синтаксис

    constant-expression:
        conditional-expression

  • Описание
    • Константное выражение может быть вычислено на этапе компиляции и использовано в любом месте, где может быть литерал.
  • Ограничения
    • Константные выражения не могут содержать присваиваний, инкрементов, декрементов и вызовов функций.

7. Объявления

  • Синтаксис

    declaration:
        variable-declaration;
        function-declaration;
        type-definition;

  • Ограничения
    • В любой области видимости должно быть не больше одного объявления идентификатора, за исключением функций, как описано в разделе 9.1. Определения функций.
  • Семантика
    • Объявление определяет интерпретацию набора идентификаторов.
    • Определение идентификатора – это объявление, которое:
      • для объекта приводит к выделению памяти для этого объекта;
      • для функции включает тело функции;
      • для определений типов и констант перечисления является единственным объявлением идентификатора.

7.1. Спецификаторы типов

  • Синтаксис

    type-specifier:
        void
        bool
        char
        short
        int
        long
        float
        double
        FILE
        struct-specifier
        enum-specifier
        typedef-name

  • Синтаксис
    • Сопоставление типов ключевым словам описано в разделе 2.3. Типы.
    • Спецификаторы структур описаны в разделе 7.1.1. Спецификаторы структур.
    • Спецификаторы перечислений описаны в разделе 7.1.2. Спецификаторы перечислений.
    • Имена определенных типов описаны в разделе 7.5. Определения типов.

7.1.1. Спецификаторы структур

  • Синтаксис

    struct-specifier:
        structidentifier ₒₚₜ {struct-declaration-list}
        structidentifier

    struct-declaration-list:
        struct-declaration
        struct-declaration-liststruct-declaration

    struct-declaration:
        type-specifierdeclarator;
        function-declaration;

  • Ограничения
    • Структура не может содержать поле неполного или функционального типа (поэтому структура не может содержать экземпляр самой себя, но может содержать указатель на экземпляр самой себя).
  • Семантика
    • Как было описано в разделе 2.3. Типы, структура - это тип, состоящий из последовательности полей, расположенных в памяти последовательно в обозначенном порядке.
    • Если заголовок объявления структуры содержит идентификатор, то он является именем типа этой структуры, и может использоваться как typedef-name.
    • Конструкция struct-declaration-list объявляет новый тип в соответствующей области видимости. Этот тип не является полным, пока не достигнута }, оканчивающая список полей структуры.

7.1.2. Спецификаторы перечислений

  • Синтаксис

    enum-specifier:
        enumidentifier ₒₚₜ {enumerator-list}
        enumidentifier ₒₚₜ {enumerator-list,}
        enumidentifier

    enumerator-list:
        enumerator
        enumerator-list,enumerator

    enumerator:
        identifier
        identifier=constant-expression

  • Ограничения
    • Выражение, обозначающее значение константы перечисления, должно иметь целочисленный тип.
  • Семантика
    • Конструкция enumerator-list объявляет новый тип в соответствующей области видимости. Этот тип не является полным, пока не достигнута }, оканчивающая список констант перечисления.
    • Если заголовок объявления перечисления содержит идентификатор, то он является именем типа этого перечисления, и может использоваться как typedef-name.
    • Идентификаторы из списка перечисления объявляются как константы целочисленного типа. Конструкция enumerator c = определяет константу перечисления как значение константного выражения. Если первая конструкция enumerator в списке перечисления не имеет =, то значение соответствующей константы равно 0. Каждая последующая конструкция enumerator без = определяет константу со значением, получаемым прибавлением 1 к значению предыдущей константы.
    • Значения констант одного и того же перечисления могут повторяться.

7.2. Объявления переменных

  • Синтаксис

    variable-declaration:
        type-specifierinit-declarator-list ₒₚₜ

    init-declarator-list:
        init-declarator
        init-declarator-list,init-declarator

    init-declarator:
        declarator
        declarator=initializer

    declarator:
        * ₒₚₜ direct-declarator

    direct-declarator:
        identifier
        direct-declarator[assignment-expression ₒₚₜ ]

  • Ограничения
    • Объявление должно содержать хотя бы одно описание типа структуры или перечисления или хотя бы один декларатор.
    • К концу объявления тип объявляемого объекта должен быть полным.
  • Семантика
    • Каждый декларатор объявляет один идентификатор, и для каждого его появления в выражении указывает область видимости и тип, заданный спецификаторами объявления.
    • В объявлении вида T D, где T обозначает спецификатор типа, а D - декларатор, содержащий некоторый идентификатор, тип, указанный для этого идентификатора, описывается индуктивно с использованием этой нотации.
    • Если в объявлении T D, где T обозначает спецификатор типа, а D - декларатор, D имеет форму identifier, то декларатор объявляет переменную с именем идентификатора и типом T.

7.2.1. Деклараторы указателей

  • Семантика
    • Если в объявлении T D1, где T обозначает спецификатор типа, а D1 - декларатор, D1 имеет форму *D, и объявление T D задает объявляемому идентификатору тип T, то идентификатору задается тип указатель на Т.

7.2.2. Деклараторы массивов

  • Ограничения
    • Если [] содержат выражение, то это выражение описывает размер массива и должно иметь целочисленный тип. Если выражение является константным, то его значение должно быть больше нуля.
    • Тип элемента в деклараторе массива не должен быть функциональным.
  • Семантика
    • Если в объявлении T D1, где T обозначает спецификатор типа, а D1 - декларатор, D1 имеет форму D[N], и объявление T D задает объявляемому идентификатору тип T, то идентификатору задается тип массив из N элементов типа Т, где N вычисляется при достижении данного объявления.
    • Если в объявлении T D1, где T обозначает спецификатор типа, а D1 - декларатор, D1 имеет форму D[], и объявление T D задает объявляемому идентификатору тип T, то идентификатору задается тип массив элементов типа Т, а размер будет задан инициализатором.
    • Если выражение размера массива отсутствует, то тип описанного массива является неполным. Он может быть дополнен инициализатором.
    • Когда значение выражения, обозначающего размер массива, будет вычислено, оно должно быть больше 0. Размер массива не меняется в течении всего его времени жизни.

7.3. Объявления функций

  • Синтаксис

    function-declaration:
        return-type-specifierfunction-declarator(parameter-list ₒₚₜ )

    return-type-specicifier:
        type-specifier* ₒₚₜ
        return-type-specicifier[constant-expression ₒₚₜ ]

    function-declarator:
        identifier
        (*identifier)

    parameter-list:
        parameter-declaration
        parameter-list,parameter-declaration

    parameter-declaration:
        type-name
        type-specifierdeclarator
        function-declaration

  • Ограничения
    • Объявляемая функция не может возвращать значение функционального типа.
    • Выражение, обозначающее размер возвращаемого массива должно иметь целочисленный тип.
  • Семантика
    • Если в объявлении T D, где T обозначает возвращаемый тип, а D - декларатор функции, T имеет форму type-specifier, то возвращаемый тип задается соответсвенно спецификатору типа, как это было описано в разделе 2.3. Типы.
    • Если в объявлении T1 D, где T1 обозначает возвращаемый тип, а D - декларатор функции, T1 имеет форму Т*, и объявление T задает возвращаемый тип T, то возвращаемый тип задается как указатель на Т.
    • Если в объявлении T1 D, где T1 обозначает возвращаемый тип, а D - декларатор функции, T1 имеет форму T[N], и T задает возвращаемый тип T, то возвращаемый тип задается как массив из N элементов типа Т, где N вычисляется при достижении данного объявления.
    • Если в объявлении T1 D, где T1 обозначает возвращаемый тип, а D - декларатор функции, T1 имеет форму T[], и T задает возвращаемый тип T, то возвращаемый тип задается как массив элементов типа Т.
    • Если в объявлении декларатор функции имеет форму identifier, то объявление объявляет функцию с параметрами, обозначенными списком параметров и возвращающую значение такого типа, как было описано выше.
    • Если в объявлении декларатор функции имеет форму (*identifier), то объявление объявляет указатель на функцию с параметрами, обозначенными списком параметров и возвращающую значение такого типа, как было описано выше.
    • Список параметров определяет типы и имена для параметров функции.
    • Параметр, определенный типом функция преобразуется в параметр с типом указатель на функцию.

7.4. Определения типа

  • TODO

7.5. Имена типов

  • Синтаксис

    type-name:
        variable-type-name
        function-type-name

    variable-type-name:
        type-specifier* ₒₚₜ abstract-declarator ₒₚₜ

    abstract-declarator:
        abstract-declarator ₒₚₜ [assignment-expression ₒₚₜ ]

    function-type-name:
        return-type-specifierfunction-pointer ₒₚₜ (parameter-list ₒₚₜ )

    function-pointer:
        (*)

  • Семантика
    • В некоторых контекстах необходимо указать тип. Это достигается при помощи конструкции имя типа, которая позволяет объявить объект или функцию, опуская идентификатор.

7.6. Инициализаторы

  • Синтаксис

    initializer:
        assignment-expression
        {initializer-list}
        {initializer-list,}

    initializer-list:
        initializer
        initializer-list,initializer

  • Ограничения
    • Инициализатор для скалярного объекта должен быть одиночным выражением.
    • Инициализатор для агрегатного объекта должен быть списком инициализации, как описано ниже, либо одиночным выражением совместимого типа.
    • Если инициализатор агрегатного объекта имеет форму списка инициализации, то список должен содержать соответствующее количество подвыражений, равное количеству элементов массива или количеству полей структуры.
    • Одно из следующих условий должно выполняться для инициализируемого объекта и для инициализатора:
      • Объект имеет вещественный тип, и правый операнд имеет целочисленный тип;
      • Левый операнд имеет тип указатель, и правый операнд является литералом null;
      • Операнды имеют совместимые типы.
  • Семантика
    • Инициализатор определяет начальное значение, хранимое в объекте.
    • Если объект не инициализируется явно, то:
      • если объект имеет тип указатель, он инициализируется константой нулевого указателя;
      • если объект имеет арифметический тип, он инициализируется нулем;
      • если объект имеет агрегатный тип, каждый его элемент инициализируется по этим правилам.
    • Каждый элемент списка инициализации инициализирует соответствующий элемент агрегатного объекта: элементы массива в порядке возрастания индекса, поля структур в порядке их объявления. Инициализация происходит в этом же порядке.
    • Если в объявлении со списком инициализации агрегатный объект содержит агрегатные объекты, то правила инициализации применяются рекурсивно для соответствующего вложенного списка.
    • Если инициализируется массив неизвестной длины, то его размер определяется количеством элементов списка инициализации. К концу инициализации массив имеет полный тип.

8. Операторы

  • Синтаксис

    statement:
        labeled-statement
        compound-statement
        expression-statement
        selection-statement
        iteration-statement
        jump-statement

  • Семантика
    • Оператор обозначает действие. Операторы исполняются последовательно.
    • Блок позволяет сгруппировать набор объявлений и операторов в одну синтаксическую единицу. Значения выражений, обозначающих длины массивов, и значения инициализаторов объектов будут вычислены тогда, когда объявление будет достигнуто в порядке исполнения.

8.1. Помеченные операторы

  • Синтаксис

    labeled-statement:
        caseconstant-expression:statement
        default:statement

  • Ограничения
    • Метки case и default должны появляться только в операторе switch. Прочие ограничения на эти метки описаны в разделе "Оператор switch".

8.2. Составной оператор

  • Синтаксис

    compound-statement:
        {block-item-list ₒₚₜ }

    block-item-list:
        block-item
        block-item-listblock-item

    block-item:
        declaration
        statement

  • Семантика
    • Составной оператор - это блок.

8.3. Оператор-выражение и пустой оператор

  • Синтаксис

    expression-statement:
        expression ₒₚₜ ;

  • Семантика
    • Выражение оператора-выражения вычисляется для его побочных эффектов (например, присваиваний и вызовов функций).
    • Пустой оператор (состоящий только из ;) не производит операций.
    • ПРИМЕР 1. В программе:
      char *s;
      /* ... */
      while (*s++ != '\0')
        ;
      пустой оператор используется для предоставления пустого тела цикла оператору итерации.
    • ПРИМЕР 2. Пустой оператор может использоваться для установки метки прямо перед закрывающей скобкой } составного оператора:
      while (loop1) { 
        /* ... */
        while (loop2) { 
          /* ... */
          if (want_out)
            goto end_loop1;
          /* ... */
        }
        /* ... */ 
      end_loop1: ;
      }

8.4. Операторы ветвления

  • Синтаксис

    selection-statement:
        if(expression)statement
        if(expression)statementelsestatement
        switch(expression)statement

  • Семантика
    • Оператор ветвления выбирает среди набора операторов в зависимости от значения управляющего выражения.
    • Оператор ветвления - это блок, область видимости которого является строгим подмножеством области видимости включающего его блока. Каждый вложенный оператор также является блоком, область видимости которого является строгим подмножеством области видимости оператора ветвления.

8.4.1. Оператор if

  • Ограничения
    • Управляющее выражение оператора if должно иметь скалярный тип.
  • Семантика
    • В обеих формах первый вложенный оператор исполняется, если значение управляющего выражения не равно 0. В форме else второй вложенный оператор исполняется, если значение управляющего выражения равно 0. Если первый вложенный оператор достигнут с помощью перехода на метку, второй вложенный оператор не исполняется.
    • else ассоциировано с ближайшим в лексическом смысле предыдущим if.

8.4.2. Оператор switch

  • Ограничения
    • Управляющее выражение оператора switch должно иметь целочисленный тип.
    • Выражение каждой метки case должно быть целочисленным константным выражением и никакие два выражения меток case в одном операторе switch не должны иметь совпадающих значений после преобразований.
    • В операторе switch должно быть не больше одной метки default.
    • Вложенный оператор switch может иметь свою метку default, а значения выражений меток case могут дублировать значения выражений меток case внешнего оператора switch.
  • Семантика
    • Оператор switch заставляет поток управления переходить к телу оператора, в или за него, в зависимости от значения управляющего выражения, а также от наличия метки default и значений любых меток case внутри тела оператора. Метка case или default доступна только внутри ближайшего включающего оператора switch.
    • Если значение выражения метки case совпадает со значением управляющего выражения, поток исполнения переходит к оператору, следующему за этой меткой. Если таких меток case нет, но есть метка default, поток исполнения переходит к помеченному оператору. Если значения никаких выражений меток case не совпадают со значением управляющего выражения, и нет метки default, никакая часть оператора switch не исполняется.
    • ПРИМЕР. В программе:
      switch (expr) {
        int i = 4;
        f(i);
      case 0:
        i = 17;
        /* falls through into default code */
      default:
        printf("%d\n", i);
      }
      объект с идентификатором i не будет инициализирован. Если значение управляющего выражения не равно 0, функция printf обратится к неопределенному значению. Аналогично, вызов функции f не будет исполнен.

8.5. Операторы итераций

  • Синтаксис

    iteration-statement:
        while( expression)statement
        dostatementwhile(expression);
        for(expression ₒₚₜ ;expression ₒₚₜ ;expression ₒₚₜ )statement
        for(declarationexpression ₒₚₜ ;expression ₒₚₜ )statement

  • Ограничения
    • Управляющее выражение оператора итерации должно иметь скалярный тип.
  • Семантика
    • Оператор итерации вызывает повторное выполнение оператора, называемого телом цикла, до тех пор, пока результат управляющего выражения не станет равным 0.
    • Оператор итерации - это блок, область видимости которого является строгим подмножеством области видимости включающего его блока. Тело цикла также является блоком, область видимости которого является строгим подмножеством области видимости оператора итерации.

8.5.1. Оператор while

  • Вычисление управляющего выражения происходит перед каждым исполнением тела цикла.

8.5.2. Оператор do

  • Вычисление управляющего выражения происходит после каждого исполнения тела цикла.

8.5.3. Оператор for

  • Оператор вида
    for(clause-1;expression-2;expression-3)statement
    ведет себя следующим образом: выражение expression-2 является управляющим выражением, которое вычисляется перед каждым выполнением тела цикла. Выражение expression-3 вычисляется после каждого выполнения тела цикла. Если clause-1 является объявлением, область видимости любых объявляемых им переменных - это оставшаяся часть объявления и весь цикл, включая два других выражения; оно исполняется перед первым вычислением управляющего выражения. Если clause-1 является выражением, оно вычисляется перед первый вычислением управляющего выражения. Таким образом, clause-1 определяет инициализацию цикла, возможно, объявляя одну или несколько переменных для использования в цикле; управляющее выражение expression-2 определяет вычисление, выполняемое перед каждой итерацией, так что выполнение цикла продолжается до тех пор, пока результат выражения не станет равным 0; а expression-3 определяет операцию (например, инкремент), которая выполняется после каждой итерации.
  • И clause-1, и expression-3 могут быть опущены. Опущенное expression-2 заменяется ненулевой константой.

8.6. Операторы перехода

  • Синтаксис

    jump-statement:
        continue;
        break;
        returnexpression ₒₚₜ ;

  • Семантика
    • Оператор перехода означает безусловный переход.

8.6.1. Оператор continue

  • Ограничения
    • Оператор continue должен появляться только в теле (или быть телом) или оператора итерации.
  • Семантика
    • Оператор continue завершает исполнение текущей итерации цикла и переходит к следующей.
    • ПРИМЕР. В программе:
      for (/* ... */) {
        /* ... */
        continue;
        /* ... */
        contin:;
      }
      оператор continue эквивалентен оператору goto contin;.

8.6.2. Оператор break

  • Ограничения
    • Оператор break должен появляться только в теле (или быть телом) оператора switch или оператора итерации.
  • Семантика
    • Оператор break завершает исполнение наименьшего по включению оператора switch или цикла.

8.6.3. Оператор return

  • Ограничения
    • Оператор return с выражением не должен появляться в функции, возвращающей значение типа void. Оператор return без выражения должен появляться только в функции, возвращающей значение типа void.
  • Семантика
    • Оператор return завершает исполнение текущей функции и возвращает управление ее вызывающей стороне. Функция может иметь любое количество операторов return.
    • Если исполняется оператор return с выражением, значение выражения возвращается вызывающей стороне как значение выражения вызова функции. Если выражение имеет тип, отличный от типа возвращаемого значения функции, в которой оно появляется, значение преобразуется, как если бы оно было присвоено объекту, имеющему тип возвращаемого значения функции.

9. Глобальные определения

  • Синтаксис

    translation-unit:
        external-declaration
        translation-unitexternal-declaration

    external-declaration:
        declaration
        function-definition

  • Семантика
    • Текст программы после подстановок препроцессора называется единицей трансляции и состоит из последовательности внешних объявлений. Они называются "внешними", так как находятся вне какой-либо функции.

9.1. Определения функций

  • Синтаксис

    function-definition:
        function-declarationcompound-statement

  • Ограничения
    • Возвращаемый тип функции должен быть пустым или любым объектным типом.
    • Если декларатор содержит список параметров, то объявление каждого параметра должно содержать имя.
  • Семантика
    • Декларатор в определении функции обозначает имя описываемой функции и идентификаторы ее параметров.
    • Составной оператор в определении функции обозначает тело функции.
    • Каждый идентификатор параметра является lvalue, который фактически объявлен в начале тела функции (и потому не может быть переопределено в теле функции кроме как во включающем блоке).
    • При входе в функцию подсчитываются выражения размеров массивов, а значения каждого аргумента конвертируются к типу соответствующего параметра как если бы они были инициализированы.
    • После инициализации всех параметров исполняется тело функции.
    • Если достигнута }, завершающая определение функции, и значение вызова этой функции использовано вызывающим, поведение не определено.

9.2. Внешние объявления объектов

  • Семантика
    • Если объявление идентификатора имеет глобальную область видимости, то оно является внешним объявлением идентификатора.
    • Если внешнее объявление не содержит инициализатор, и описываемый идентификатор имеет тип, отличный от функционального, то идентификатор инициализируется начальным значением, как было описано в разделе Инициализаторы.
    • Вычисление значений внешних объектов происходит в порядке их появления в единице трансляции при запуске программы.

10. Директивы препроцессора

  • TODO
Clone this wiki locally