Выбрать главу

Тип void не фигурировал в первом издании этой книги, однако за прошедшее время стал общеупотребительным.

А6.8. Указатели на void

Любой указатель на объект можно привести к типу void * без потери информации. Если результат подвергнуть обратному преобразованию, то мы получим прежний указатель. В отличие от преобразований указатель-в-указатель (рассмотренных в A6.6), которые требуют явных операторов приведения к типу, в присваиваниях и сравнениях указатель любого типа может выступать в паре с указателем типа void * без каких-либо предварительных преобразований типа.

Такая интерпретация указателей void * - новая; ранее роль обобщенного указателя отводилась указателю типа char *. Стандарт ANSI официально разрешает использование указателей void * совместно с указателями других типов в присваиваниях и сравнениях; в иных комбинациях указателей стандарт требует явных преобразований типа.

A7. Выражения

Приоритеты описываемых операторов имеют тот же порядок, что и пункты данного параграфа (от высших к низшим). Например, для оператора +, описанного в A7.7, термин "операнды" означает "выражения, определенные в A7.1-A7.6". В каждом пункте описываются операторы, имеющие одинаковый приоритет, и указывается их ассоциативность (левая или правая). Приоритеты и ассоциативность всех операторов отражены в грамматике, приведенной в A13.

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

Это правило отменяет ранее предоставлявшуюся свободу в выборе порядка выполнения операций, которые математически коммутативны и ассоциативны, но которые в процессе вычислений могут таковыми не оказаться. Это изменение затрагивает только вычисления с плавающей точкой, выполняющиеся "на грани точности", и ситуации, когда возможно переполнение.

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

A7.1. Генерация указателя 

Если тип выражения или подвыражения есть "массив из T", где T - некоторый тип, то значением этого выражения является указатель на первый элемент массива, и тип такого выражения заменяется на тип "указатель на T". Такая замена не делается, если выражение является операндом унарного оператора amp;, или операндом операций ++, --, sizeof, или левым операндом присваивания, или операндом оператора . (точка). Аналогично, выражение типа "функция, возвращающая Т", кроме случая, когда оно является операндом для&, преобразуется в тип "указатель на функцию, возвращающую T".

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

Первичные выражения это идентификаторы, константы, строки и выражения в скобках.

первичное - выражение:

    идентификатор

    константа

    строка

    (выражение)

Идентификатор, если он был должным образом объявлен (о том, как это делается, речь пойдет ниже), - первичное выражение. Тип идентификатора специфицируется в его объявлении. Идентификатор есть lvalue, если он обозначает объект (A5) арифметического типа, либо объект типа "структура", "объединение" или "указатель".

Константа - первичное выражение. Ее тип зависит от формы записи, которая была рассмотрена в A2.5.

Строковый литерал - первичное выражение. Изначально его тип - "массив из char" ("массив из wchar_t" для строки символов расширенного набора), но в соответствии с правилом, приведенным в A7.1, указанный тип обычно превращается в "указатель на char" ("указатель на wchar_t") с результирующим значением "указатель на первый символ строки". Для некоторых инициализаторов такая замена типа не делается. (см. A8.7)

Выражение в скобках - первичное выражение, тип и значение которого идентичны типу и значению этого же выражения без скобок. Наличие или отсутствие скобок не влияет на то, является ли данное выражение lvalue или нет.

A7.3. Постфиксные выражения

В постфиксных выражениях операторы выполняются слева направо.

постфиксное-выражение:

    первичное-выражение

    постфиксное-выражение [выражение]

    постфиксное-выражение (список-аргументов-выраженийнеоб)

    постфиксное-выражение.идентификатор

    постфиксное-выражение->идентификатор

    постфиксное-выражение ++

    постфиксное-выражение --

список-аргументов-выражений:

    выражение-присваивание

    список-аргументов-выражений , выражение-присваивание

A7.3.1. Обращение к элементам массива

Постфиксное выражение, за которым следует выражение в квадратных скобках, есть постфиксное выражение, обозначающее обращение к индексируемому массиву. Одно из этих двух выражений должно принадлежать типу "указатель на T", где T - некоторый тип, а другое - целочисленному типу; тип результата индексирования есть T. Выражение E1[E2] по определению идентично выражению *((E1)+(E2)). Подробности см. в A8.6.

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

Вызов функции есть постфиксное выражение (оно называется именующим выражением функции - function designator), за которым следуют скобки, содержащие (возможно пустой) список разделенных запятыми выражений-присваиваний (A7.17), представляющих собой аргументы этой функции. Если постфиксное выражение - идентификатор, не объявленный в текущей области видимости, то считается, что этот идентификатор как бы неявно описан объявлением

extern int identifier();

помещенным в самом внутреннем блоке, содержащем вызов соответствующей функции. Постфиксное выражение (после, возможно неявного, описания и генерации указателя, см. A7.1) должно иметь тип "указатель на функцию, возвращающую T", где T - тип возвращаемого значения.