Опубликован: 05.07.2006 | Доступ: свободный | Студентов: 4680 / 885 | Оценка: 4.12 / 3.74 | Длительность: 18:59:00
Лекция 10:

Справочное руководство по языку C

< Лекция 9 || Лекция 10: 1234567891011

9.7. Выражения

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

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

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

9.7.1 Первичные выражения

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Унарное-выражение:

  • * выражение
  • & L-значение
  • - выражение
  • ! выражение
  • ~ выражение
  • ++ L-значение
  • -- L-значение
  • L-значение ++
  • L-значение --
  • (имя- типа ) выражение
  • sizeof выражение
  • sizeof имя- типа

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • выражение * выражение
  • выражение / выражение
  • выражение % выражение

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

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

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

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

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

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

  • выражение + выражение
  • выражение - выражение

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

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

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

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

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

< Лекция 9 || Лекция 10: 1234567891011