Затем, если какой-либо операнд имеет тип DOUBLE, то другой
преобразуется к типу DOUBLE, и это будет типом результата.
В противном случае, если какой-либо операнд имеет тип LONG,
то другой операнд преобразуется к типу LONG, и это и будет
типом результата.
В противном случае, если какой-либо операнд имеет тип
UNSIGNED, то другой операнд преобразуется к типу UNSIGNED,
и это будет типом результата.
В противном случае оба операнда будут иметь тип INT, и это
будет типом результата.
15. Выражения
Старшинство операций в выражениях совпадает с порядком
следования основных подразделов настоящего раздела, начиная
с самого высокого уровня старшинства. Так, например, выраже-
ниями, указываемыми в качестве операндов операции +
(п.15.4), Являются выражения, определенные в п.п.15.1-15.3.
Внутри каждого подраздела операции имеет одинаковое старшин-
ство. В каждом подразделе для описываемых там операций ука-
зывается их ассоциативность слева или справа. Старшинство и
ассоциативность всех операций в выражениях резюмируются в
грамматической сводке в п.18.
В противном случае порядок вычислений выражений не опре-
делен. В частности, компилятор считает себя в праве вычис-
лять подвыражения в том порядке, который он находит наиболее
эффективным, даже если эти подвыражения приводят к побочным
эффектам. Порядок, в котором происходят побочные эффекты, не
специфицируется. Выражения, включающие коммутативные и ассо-
циативные операции ( *,+,&,!,^ ), могут быть переупорядочены
произвольным образом даже при наличии круглых скобок; чтобы
вынудить определенный порядок вычислений, в этом случае не-
обходимо использовать явные промежуточные переменные.
· 192 -
При вычислении выражений обработка переполнения и про-
верка при делении являются машинно-зависимыми. Все существу-
ющие реализации языка “C” игнорируют переполнение целых; об-
работка ситуаций при делении на 0 и при всех особых случаях
с плавающими числами меняется от машины к машине и обычно
выполняется с помощью библиотечной функции.
15.1. Первичные выражения
Первичные выражения, включающие ., ->, индексацию и об-
ращения к функциям, группируются слева направо.
Первичное выражение:
идентификатор
константа
строка
(выражение)
первичное-выражение [выражение]
первичное-выражение (список-выражений нео
первичное-L-значение . Идентификатор
первичное-выражение -> идентификатор
список-выражений:
выражение
список-выражений, выражение
Идентификатор является первичным выражением при условии, что
он описан подходящим образом, как это обсуждается ниже. тип
идентификатора определяется его описанием. Если, однако, ти-
пом идентификатора является “массив ...”, то значением выра-
жения, состоящего из этого идентификатора , является указа-
тель на первый объект в этом массиве, а типом выражения бу-
дет “указатель на ...”. Более того, идентификатор массива не
является выражением L-значения. подобным образом идентифика-
тор, который описан как “функция, возвращающая ...”, за иск-
лючением того случая, когда он используется в позиции имени
функции при обращении, преобразуется в “указатель на функ-
цию, которая возвращает ...”.
Константа является первичным выражением. В зависимости
от ее формы типом константы может быть INT, LONG или DOUBLE.
Строка является первичным выражением. Исходным ее типом
является “массив символов”; но следуя тем же самым правилам,
которые приведены выше для идентификаторов, он модифицирует-
ся в “указатель на символы”, и результатом является указа-
тель на первый символ строки. (имеется исключение в некото-
рых инициализаторах; см. П. 16.6.)
Выражение в круглых скобках является первичным выражени-
ем, тип и значение которого идентичны типу и значению этого
выражения без скобок. Наличие круглых скобок не влияет на
то, является ли выражение L-значением или нет.
· 193 -
Первичное выражение, за которым следует выражение в
квадратных скобках, является первичным выражением. Интуитив-
но ясно, что это выражение с индексом. Обычно первичное вы-
ражение имеет тип “указатель на ...”, индексное выражение
имеет тип INT, а типом результата является “...”. Выражение
E1[E2] по определению идентично выражению * ((E1) + (E2)).
Все, что необходимо для понимания этой записи, содержится в
этом разделе; вопросы, связанные с понятием идентификаторов
и операций * и + рассматриваются в п.п. 15.1, 15.2 И 15.4
соответственно; выводы суммируются ниже в п. 22.3.
Обращение к функции является первичным выражением, за
которым следует заключенный в круглые скобки возможно пустой
список выражений, разделенных запятыми, которые и представ-
ляют собой фактические аргументы функции. Первичное выраже-
ние должно быть типа “функция, возвращающая ...”, а резуль-
тат обращения к функции имеет тип “...”. Как указывается ни-
же, ранее не встречавщийся идентификатор, за которым непос-
редственно следует левая круглая скобка, считается описанным
по контексту, как представляющий функцию, возвращающую це-
лое; следовательно чаще всего встречающийся случай функции,
возвращающей целое значение, не нуждается в описании.
Перед обращением любые фактические аргументы типа FLOAT
преобразуются к типу DOUBLE, любые аргументы типа CHAR или
SHORT преобразуются к типу INT, и, как обычно, имена масси-
вов преобразуются в указатели. Никакие другие преобразования
не выполняются автоматически; в частности, не сравнивает ти-
пы фактических аргументов с типами формальных аргументов.
Если преобразование необходимо, используйте явный перевод
типа (CAST); см. П.п. 15.2, 16.7.
При подготовке к вызову функции делается копия каждого
фактического параметра; таким образом, все передачи аргумен-
тов в языке “C” осуществляются строго по значению. функция
может изменять значения своих формальных параметров, но эти
изменения не влияют на значения фактических параметров. С
другой строны имеется возможность передавать указатель при
таком условии, что функция может изменять значение объекта,
на который этот указатель указывает. Порядок вычисления ар-
гументов в языке не определен; обратите внимание на то, что
различные компиляторы вычисляют по разному.
Допускаются рекурсивные обращения к любой функции.
Первичное выражение, за которым следует точка и иденти-
фикатор, является выражением. Первое выражение должно быть
L-значением, именующим структуру или объединение, а иденти-
фикатор должен быть именем члена структуры или объединения.
Результатом является L-значение, ссылающееся на поименован-
ный член структуры или объединения.
Первичное выражение, за которым следует стрелка (состав-
ленная из знаков - и >) и идентификатор, является выражени-
ем. первое выражение должно быть указателем на структуру или
объединение, а идентификатор должен именовать член этой
структуры или объединения. Результатом является L-значение,
ссылающееся на поименованный член структуры или объединения,
на который указывает указательное выражение.
Следовательно, выражение E1->MOS является тем же самым,
что и выражение (*E1).MOS. Структуры и объединения рассмат-
риваются в п. 16.5. Приведенные здесь правила использования
структур и объединений не навязываются строго, для того что-
бы иметь возможность обойти механизм типов. См. П. 22.1.
· 194 -
15.2. Унарные операции
Выражение с унарными операциями группируется справо на-
лево.
Унарное-выражение:
· выражение
& L-значение
· выражение
! Выражение
\^ выражение
++ L-значение
· L-значение
L-значение ++
L-значение—
(имя-типа) выражение
SIZEOF выражение
SIZEOF имя-типа
Унарная операция * означает косвенную адресацию: выраже-
ние должно быть указателем, а результатом является L-значе-
ние, ссылающееся на тот объект, на который указывает выраже-
ние. Если типом выражения является “указатель на...”, то ти-
пом результата будет “...”.
Результатом унарной операции & является указатель на
объект, к которому ссылается L-значение. Если L-значение
имеет тип “...”, то типом результата будет “указатель на
...”.
Результатом унарной операции - (минус) является ее опе-
ранд, взятый с противоположным знаком. Для величины типа
UNSIGNED результат получается вычитанием ее значения из 2**N
(два в степени N), где N-число битов в INT. Унарной операции
+ (плюс) не существует.
Результатом операции логического отрицания ! Является 1,
если значение ее операнда равно 0, и 0, если значение ее
операнда отлично от нуля. Результат имеет тип INT. Эта опе-
рация применима к любому арифметическому типу или указате-
лям.
Операция \^ дает обратный код, или дополнение до едини-
цы, своего операнда. Выполняются обычные арифметические пре-
образования. Операнд должен быть целочисленного типа.
Объект, на который ссылается операнд L-значения префикс-
ной операции ++, увеличивается. значением является новое
значение операнда, но это не L-значение. Выражение ++х экви-
валентно х+=1. Информацию о преобразованиях смотри в разборе
операции сложения (п. 15.4) и операции присваивания (п.
15.14).
Префиксная операция—аналогична префиксной операции
++, но приводит к уменьшению своего операнда L-значения.
При применении постфиксной операции ++ к L-значению ре-
зультатом является значение объекта, на который ссылается
L-значение. После того, как результат принят к сведению,
объект увеличивается точно таким же образом, как и в случае
префиксной операции ++. Результат имеет тот же тип, что и
выражение L-значения.
· 195 -
При применении постфиксной операции—к L-значению ре-
зультатом является значение объекта, на который ссылается