Kernighan, B. W. and Ritchie, D. M. "The 'C' Programming Language"; Chapter 16

16. Выражения.

Старшинство операций в выражениях совпадает с порядком следованияосновных подразделов настоящего раздела, начиная с самого высокогоуровня старшинства. Так, например, выражениями, указываемыми вкачестве операндов операции + (п. 16.4),являются выражения,определенные в п.п. 16.1-16.3. Внутри каждого подраздела операции имеетодинаковое старшинство. В каждом подразделе для описываемых тамопераций указывается их ассоциативность слева или справа. Старшинствои ассоциативность всех операций в выражениях резюмируются вграмматической сводке в п. 27.

В противном случае порядок вычислений выражений не определен.В частности, компилятор считает себя в праве вычислять подвыраженияв том порядке, который он находит наиболее эффективным, даже если этиподвыражения приводят к побочным эффектам. Порядок, в которомпроисходят побочные эффекты, не специфицируется. Выражения, включающиекоммутативные и ассоциативные операции ( *,+,&,!,^ ), могут бытьпереупорядочены произвольным образом даже при наличии круглых скобок;чтобы вынудить определенный порядок вычислений, в этом случаенеобходимо использовать явные промежуточные переменные.

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

Содержание

16.1. Первичные выражения.
16.2. Унарные операции.
16.3. Мультипликативные операции
16.4. Аддитивные операции.
16.5. Операции сдвига.
16.6. Операции отношения.
16.7. Операции равенства.
16.8. Побитовая операция 'и'
16.9. Побитовая операция исключающего 'или'
16.10. Побитовая операция включающего 'или'
16.11. Логическая операция 'и'
16.12. Операция логического 'или'
16.13. Условная операция.
16.14. Операция присваивания
16.15. Операция запятая.


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

Первичные выражения, включающие ., ->, индексацию и обращения кфункциям, группируются слева направо.

Первичное выражение:
идентификатор
константа
строка
(выражение)
первичноe-выражение [выражение]
первичноe-выражение (список-выраженийнеоб)
первичноe-l-значение . идентификатор
первичноe-выражение -> идентификатор

Список-выражений:
выражение
список-выражений, выражение

Идентификатор является первичным выражением при условии, что онописан подходящим образом, как это обсуждается ниже. Тип идентификатораопределяется его описанием. Если, однако, типом идентификатора является"массив ...", то значением выражения, состоящего из этого идентификатора, является указатель на первый об'ект в этом массиве, а типом выражениябудет "указатель на ...". Более того, идентификатор массива не являетсявыражением l-значения. Подобным образом идентификатор, который описанкак "функция, возвращающая ...", за исключением того случая, когда ониспользуется в позиции имени функции при обращении, преобразуется в"указатель на функцию, которая возвращает ...".

Константа является первичным выражением. В зависимости от ее формытипом константы может быть int, long или double.

Строка является первичным выражением. Исходным ее типом является"массив символов"; но следуя тем же самым правилам, которые приведенывыше для идентификаторов, он модифицируется в "указатель на символы", ирезультатом является указатель на первый символ строки. (имеетсяисключение в некоторых инициализаторах; см. п. 17.6.)

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

Первичное выражение, за которым следует выражение в квадратных скобках,является первичным выражением. Интуитивно ясно, что это выражение синдексом. Обычно первичное выражение имеет тип "указатель на ...",индексное выражение имеет тип int, а типом результата является "...".Выражение е1[е2] по определению идентично выражению * ((е1) + (е2)).Все, что необходимо для понимания этой записи, содержится в этомразделе; вопросы, связанные с понятием идентификаторов и операций *и + рассматриваются в п.п. 16.2, 16.3 и 16.4 соответственно; выводысуммируются ниже в п. 23.3.

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

Перед обращением любые фактические аргументы типа float преобразуютсяк типу double, любые аргументы типа char или short преобразуются к типуint, и, как обычно, имена массивов преобразуются в указатели. Никакиедругие преобразования не выполняются автоматически; в частности, несравнивает типы фактических аргументов с типами формальных аргументов.Если преобразование необходимо, используйте явный перевод типа (cast);см. п. 16.2, 17.7.

При подготовке к вызову функции делается копия каждого фактическогопараметра; таким образом, все передачи аргументов в языке "C"осуществляются строго по значению. Функция может изменять значения своихформальных параметров, но эти изменения не влияют на значенияфактических параметров. С другой строны имеется возможность передаватьуказатель при таком условии, что функция может изменять значениеоб'екта, на который этот указатель указывает. Порядок вычисленияаргументов в языке не определен; обратите внимание на то, что различныекомпиляторы вычисляют по разному.

Допускаются рекурсивные обращения к любой функции.

Первичное выражение, за которым следует точка и идентификатор, являетсявыражением. Первое выражение должно быть l-значением, именующимструктуру или об'единение, а идентификатор должен быть именем членаструктуры или об'единения. Результатом является l-значение, ссылающеесяна поименованный член структуры или об'единения.

Первичное выражение, за которым следует стрелка (составленная из знаков- и >) и идентификатор, является выражением. Первое выражение должнобыть указателем на структуру или об'единение, а идентификатор долженименовать член этой структуры или об'единения. Результатом являетсяl-значение, ссылающееся на поименованный член структуры или об'единения,на который указывает указательное выражение.

Следовательно, выражение el->mos является тем же самым, что и выражение(*el).mos. структуры и об'единения рассматриваются в п. 17.5. Приведенныездесь правила использования структур и об'единений не навязываютсястрого, для того чтобы иметь возможность обойти механизм типов. См. п. 23.1.


16.2. Унарные операции.

Выражение с унарными операциями группируется справо налево.

Унарное-выражение:
* выражение
& l-значение
- выражение
! выражение
~ выражение
++ l-значение
-- l-значение
l-значение ++
l-значение --
(имя-типа) выражение
sizeof выражение
sizeof (имя-типа)

Унарная операция * означает косвенную адресацию: выражение должнобыть указателем, а результатом является l-значение, ссылающееся натот об'ект, на который указывает выражение. Если типом выраженияявляется "указатель на...", то типом результата будет "...".

Результатом унарной операции & является указатель на об'ект, к которомуссылается l-значение. Если l-значение имеет тип "...", то типомрезультата будет "указатель на ...".

Результатом унарной операции - (минус) является ее операнд, взятый спротивоположным знаком. Для величины типа unsigned результат получаетсявычитанием ее значения из 2**n (два в степени n), где n-число битов вint. Унарной операции + (плюс) не существует.

Результатом операции логического отрицания ! Является 1, если значениеее операнда равно 0, и 0, если значение ее операнда отлично от нуля.Результат имеет тип int. Эта операция применима к любому арифметическомутипу или указателям.

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

Об'ект, на который ссылается операнд l-значения префиксной операции ++,увеличивается. Значением является новое значение операнда, но это неl-значение. Выражение ++х эквивалентно х+=1. Информацию опреобразованиях смотри в разборе операции сложения (п. 16.4) и операции присваивания (п. 16.14).

Префиксная операция -- аналогична префиксной операции ++, но приводитк уменьшению своего операнда l-значения.

При применении постфиксной операции ++ к l-значению результатомявляется значение об'екта, на который ссылается l-значение. После того,как результат принят к сведению, об'ект увеличивается точно таким жеобразом, как и в случае префиксной операции ++. Результат имеет тот жетип, что и выражение l-значения.

При применении постфиксной операции -- к l-значению результатомявляется значение об'екта, на который ссылается l-значение. После того,как результат принят к сведению, об'ект уменьшается точно таким жеобразом, как и в случае префиксной операции --. Результат имеет тотже тип, что и выражение l-значения.

Заключенное в круглые скобки имя типа данных, стоящее перед выражением, вызывает преобразование значения этого выражения к указанному типу.Эта конструкция называется перевод (cast). Имена типов описываются вп. 17.7.

Операция sizeof выдает размер своего операнда в байтах. (понятие байт вязыке не определено, разве только как значение операции sizeof. Однаково всех существующих реализациях байтом является пространство,необходимое для хранения об'екта типа char). При применении к массивурезультатом является полное число байтов в массиве. Размер определяетсяиз описаний об'ектов в выражении. Это выражение семантически являетсяцелой константой и может быть использовано в любом месте, где требуетсяконстанта. Основное применение эта операция находит при связях спроцедурами, подобным распределителям памяти, и в системах ввода-вывода.

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

Конструкция sizeof (тип) рассматривается как целое, так что выражениеsizeof (тип) - 2 эквивалентно выражению (sizeof (тип)) - 2.


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

Мультипликативные операции *, /, и % группируются слева направо.Выполняются обычные арифметические преобразования.

Мультипликативное-выражение:
выражение * выражение
выражение / выражение
выражение % выражение

Бинарная операция * означает умножение. Операция * ассоциативна, ивыражения с несколькими умножениями на одном и том же уровне могут бытьперегруппированы компилятором.

Бинарная операция / означает деление. При делении положительных целыхосуществляется усечение по направлению к нулю, но если один из операндовотрицателен, то форма усечения зависит от используемой машины. На всехмашинах, охватываемых настоящим руководством, остаток имеет тот же знак, что и делимое. Всегда справедливо, что (a/b)*b+a%b равно a (если bне равно 0).

Бинарная операция % выдает остаток от деления первого выражения навторое. Выполняются обычные арифметические преобразования. Операндыне должны быть типа float.


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

Аддитивные операции + и - группируются слева направо. Выполняютсяобычные арифметические преобразования. Для каждой операции имеютсянекоторые дополнительные возможности, связанные с типами операндов.

Аддитивноe-выражение:
выражение + выражение
выражение - выражение

Результатом операции + является сумма операндов. Можно складыватьуказатель на об'ект в массиве и значение любого целочисленного типа.Во всех случаях последнее преобразуется в адресное смещениепосредством умножения его на длину об'екта, на который указывает этотуказатель. Результатом является указатель того же самого типа, чтои исходный указатель, который указывает на другой об'ект в том жемассиве, смещенный соответствующим образом относительно первоначальногооб'екта. Таким образом, если р является указателем об'екта в массиве,то выражение р+1 является указателем на следующий об'ект в этоммассиве.

Никакие другие комбинации типов для указателей не разрешаются.

Операция + ассоциативна, и выражение с несколькими сложениями на том жесамом уровне могут быть переупорядочены компилятором.

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

Если вычитаются два указателя на об'екты одинакового типа, то результатпреобразуется (делением на длину об'екта) к типу int, представляя собойчисло об'ектов, разделяющих указываемые об'екты. Если эти указателине на об'екты из одного и того же массива, то такое преобразование,вообще говоря, даст неожиданные результаты, потому что даже указателина об'екты одинакового типа не обязаны отличаться на величину, кратнуюдлине об'екта.


16.5. Операции сдвига.

Операции сдвига << и >> группируются слева направо. Для обеих операцийпроводятся обычные арифметические преобразования их операндов, каждыйиз которых должен быть целочисленного типа. Затем правый операндпреобразуется к типу int; результат имеет тип левого операнда. Результатне определен, если правый операнд отрицателен или больше или равен, чемдлина об'екта в битах.

Выражениe-сдвига:
выражение << выражение
выражение >> выражение

Значением выражения е1<<е2 является е1 (интерпретируемое как комбинациябитов), сдвинутое влево на е2 битов; освобождающиеся биты заполняютсянулем. Значением выражения е1>>е2 является е1, сдвинутое вправо на е2битовых позиций. Если е1 имеет тип unsigned, то сдвиг вправогарантированно будет логическим (заполнение нулем); в противном случаесдвиг может быть (и так и есть на pdp-11) арифметическим(освобождающиеся биты заполняются копией знакового бита).


16.6. Операции отношения.

Операции отношения группируются слева направо, но этот факт неочень полезен; выражение а<b<с не означает того, что оно казалось быдолжно означать.

Выражениe-отношения:
выражение < выражение
выражение > выражение
выражение <= выражение
выражение >= выражение

Операции < (меньше), > (больше), <= (меньше или равно) и >= (большеили равно) все дают 0, если указанное отношение ложно, и 1, если оноистинно. Результат имеет тип int. Выполняются обычные арифметическиепреобразования. Могут сравниваться два указателя; результат зависитот относительного расположения указываемых об'ектов в адресномпространстве. Сравнение указателей переносимо только в том случае,если указатели указывают на об'екты из одного и того же массива.


16.7. Операции равенства.

Выражениe-равенства:
выражение == выражение
выражение != выражение

Операции == (равно) и != (не равно) в точности аналогичны операциямотношения, за исключением того, что они имеют более низкий уровеньстаршинства. (поэтому значение выражения а<в==с<d равно 1 всякий раз,когда выражение а<в и с<d имеют одинаковое значение истинности).

Указатель можно сравнивать с целым, но результат будет машинно-независимым только в том случае, если целым является константа 0.Гарантируется, что указатель, которому присвоено значение 0, неуказывает ни на какой об'ект и на самом деле оказывается равным 0;общепринято считать такой указатель нулем.


16.8. Побитовая операция 'и'

Выражениe-и:
выражение & выражение

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


16.9. Побитовая операция исключающего 'или'

Выражениe-исключающего-или:
выражение ^ выражение

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


16.10. Побитовая операция включающего 'или'

Выражениe-включающего-или:
выражение | выражение

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


16.11. Логическая операция 'и'

Выражениe-логического-и:
выражение && выражение

Операция && группируется слева направо. Она возвращает 1, если оба ееоперанда отличны от нуля, и 0 в противном случае. В отличие от &операция && гарантирует вычисление слева направо; более того, еслипервый операнд равен 0, то значение второго операнда вообще невычисляется

Операнды не обязаны быть одинакового типа, но каждый из нихдолжен быть либо одного из основных типов, либо указателем.Результат всегда имеет тип int.


16.12. Операция логического 'или'

Выражениe-логического-или:
выражение || выражение

Операция || группируется слева направо. Она возвращает 1, еслиодин из операндов отличен от нуля, и 0 в противном случае. Вотличие от операции | операция || гарантирует вычисление слеванаправо; более того, если первый операнд отличен от нуля, тозначение второго операнда вообще не вычисляется.

Операнды не обязаны быть одинакового типа, но каждый из них долженбыть либо одного из основных типов, либо указателем. Результатвсегда имеет тип int.


16.13. Условная операция.

Условноe-выражение:
выражение ? выражение : выражение

Условные выражения группируются слево направо. Вычисляется значениепервого выражения, и если оно отлично от нуля, то результатом будетзначение второго выражения; в противном случае результатом будетзначение третьего выражения. Если это возможно, проводятся обычныеарифметические преобразования, с тем, чтобы привести второе и третьевыражения к общему типу; в противном случае, если оба выраженияявляются указателями одинакового типа, то результат имеет тот же тип;в противном случае одно выражение должно быть указателем, а другое -константой 0, и результат будет иметь тип указателя. Вычисляетсятолько одно из второго и третьего выражений.


16.14. Операция присваивания

Имеется ряд операций присваивания, каждая из которых группируется слеванаправо. Все операции требуют в качестве своего левого операндаl-значение, а типом выражения присваивания является тип его левогооперанда. Значением выражения присваивания является значение,хранимое в левом операнде после того, как присваивание уже будетпроизведено. Две части составной операции присваивания являютсяотдельными лексемами.

Выражениe-присваивания:
l-значение = выражение
l-значение += выражение
l-значение -= выражение
l-значение *= выражение
l-значение /= выражение
l-значение %= выражение
l-значение >>= выражение
l-значение <<= выражение
l-значение &= выражение
l-значение ^= выражение
l-значение |= выражение

Когда производится простое присваивание с'=', значение выражениязаменяет значение об'екта, на которое ссылается l-значение. Еслиоба операнда имеют арифметический тип, то перед присваиванием правыйоперанд преобразуется к типу левого операнда.

О свойствах выражения вида е1 оп = е2, где оп - одна из перечисленныхвыше операций, можно сделать вывод, если учесть, что оно эквивалентновыражению е1 = е1 оп (е2); однако выражение е1 вычисляется только одинраз. В случае операций += и -= левый операнд может быть указателем,причем при этом (целочисленный) правый операнд преобразуется такимобразом, как об'яснено в п. 16.4;все правые операнды и все отличные отуказателей левые операнды должны иметь арифметический тип.

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


16.15. Операция запятая.

Выражениe-с-запятой:
выражение, выражение

Пара выражений, разделенных запятой, вычисляется слева направо изначение левого выражения отбрасывается. Типом и значением результатаявляется тип и значение правого операнда. Эта операция группируетсяслева направо. В контексте, где запятая имеет специальное значение,как, например, в списке фактических аргументов функций (п. 16.1) или в списках инициализаторов (п. 17.6), операция запятая, описываемая вэтом разделе, может появляться только в круглых скобках; например,функция

 f(a,(t=3,t+2),c)
имеет три аргумента, второй из которых имеет значение 5.