|
Справочное руководство по языку C
9.16. Соображения о переносимости
Некоторые части языка "C" по своей сути машинно-зависимы. Следующие ниже перечисление потенциальных трудностей хотя и не являются всеобъемлющими, но выделяет основные из них.
Как показала практика, вопросы, целиком связанные с аппаратным оборудованием, такие как размер слова, свойства плавающей арифметики и целого деления, не представляют особенных затруднений. Другие аспекты аппаратных средств находят свое отражение в различных реализациях. Некоторые из них, в частности, знаковое расширение (преобразующее отрицательный символ в отрицательное целое) и порядок, в котором помещаются байты в слове, представляют собой неприятность, которая должна тщательно отслеживаться. Большинство из остальных проблем этого типа не вызывает сколько-нибудь значительных затруднений.
Число переменных типа register, которое фактически может быть помещено в регистры, меняется от машины к машине, также как и набор допустимых для них типов. Тем не менее все компиляторы на своих машинах работают надлежащим образом; лишние или недопустимые регистровые описания игнорируются.
Некоторые трудности возникают только при использовании сомнительной практики программирования. Писать программы, которые зависят от каких-либо этих свойств, является чрезвычайно неразумным.
Языком не указывается порядок вычисления аргументов функций ; они вычисляются справа налево на PDP-11 и VAX-11 и слева направо на остальных машинах. порядок, в котором происходят побочные эффекты, также не специфицируется.
Так как символьные константы в действительности являются объектами типа int, допускается использование символьных констант, состоящих из нескольких символов. Однако, поскольку порядок, в котором символы приписываются к слову, меняется от машины к машине, конкретная реализация оказывается весьма машинно-зависимой.
Присваивание полей к словам и символов к целым осуществляется справа налево на PDP-11 и VAX-11 и слева направо на других машинах. Эти различия незаметны для изолированных программ, в которых не разрешено смешивать типы (преобразуя, например, указатель на int в указатель на char и затем проверяя указываемую память), но должны учитываться при согласовании с накладываемыми извне схемами памяти.
Язык, принятый на различных компиляторах, отличается только незначительными деталями. Самое заметное отличие состоит в том, что используемый в настоящее время компилятор на PDP-11 не инициализирует структуры, которые содержат поля битов, и не допускает некоторые операции присваивания в определеных контекстах, связанных с использованием значения присваивания.
9.17. Анахронизмы
Так как язык "C" является развивающимся языком, в старых программах можно встретить некоторые устаревшие конструкции. Хотя большинство версий компилятора поддерживает такие анахронизмы, они в конце концов исчезнут, оставив за собой только проблемы переносимости.
В ранних версиях "C" для проблем присваивания использовалась форма =on, а не on=, приводя к двусмысленностям, типичным примером которых является
x = -1
где x фактически уменьшается, поскольку операции = и - примыкают друг к другу, но что вполне могло рассматриваться и как присваивание -1 к x.
Синтаксис инициализаторов изменился: раньше знак равенства, с которого начинается инициализатор, отсутствовал, так что вместо
int x = 1;
использовалось
int x 1;
изменение было внесено из-за инициализации
int f (1+2)
которая достаточно сильно напоминает определение функции, чтобы смутить компиляторы.
9.18. Сводка синтаксических правил
Эта сводка синтаксиса языка "C" предназначена скорее для облегчения понимания и не является точной формулировкой языка.
9.18.1. Выражения
Основными выражениями являются следующие:
выражение: первичное-выражение * выражение & выражение - выражение ! Выражение ^ выражение ++ l-значение -- l-значение l-значение ++ l-значение -- sizeof выражение (имя типа) выражение выражение бинарная-операция выражение выражение ? Выражение : выражение l-значение операция-присваивания выражение выражение , выражение первичное выражение: идентификатор константа строка (выражение) первичное-выражение (список выражений необ) первичное-выражение [выражение] l-значение . Идентификатор первичное выражение -> идентификатор l-значение: идентификатор первичное-выражение [выражение] l-значение . Идентификатор первичное-выражение -> идентификатор * выражение (l-значение)
Операции первичных выражений
() [] . ->
имеют самый высокий приоритет и группируются слева направо. Унарные операции
* & - ! ~ ++ -- sizeof(Имя типа)
имеют более низкий приоритет, чем операции первичных выражений, но более высокий, чем приоритет любой бинарной операции. Эти операции группируются справа налево. Все бинарные операции и условная операция (прим. перевод.: условная операция группируется справа налево; это изменение внесено в язык в 1978 г.) группируются слева направо и их приоритет убывает в следующем порядке:
Бинарные операции:
- * / %
- + -
- >> <<
- < > <= >=
- == !=
- &
- ~
- |
- &&
- ||
- ?:
Все операции присваивания имеют одинаковый приоритет и группируются справа налево. Операции присваивания:
= += -= *= ?= %= >>= <<= &= ~ = |=
Операция запятая имеет самый низкий приоритет и группируется слева направо.
9.18.2. Описания
Описание: спецификаторы-описания список-инициализируемых-описателей необ; --------------------------------------------------------- спецификаторы-описания: спецификатор-типа спецификаторы-описания необ спецификатор-класса-памяти спецификаторы-описания необ спецификатор-класса-памяти: auto static extern register typedef спецификатор-типа: char short int long unsigned float double спецификатор-структуры-или-объединения определяющее-тип-имя список-инициализируемых-описателей: инициализируемый-описатель инициализируемый-описатель, список-инициализируемых-описателей инициализируемый-описатель описатель-инициализатор необ описатель: идентификатор (описатель) * описатель описатель () описатель [константное выражение необ]
спецификатор-структуры-или-объединения: struct список-описателей-структуры struct идентификатор {список-описаний-структуры} struct идентификатор union {список-описаний-структуры} union идентификатор {список-описаний-структуры} union идентификатор список-описаний-структуры: описание-структуры описание-структуры список-описаний-структуры описание структуры: спецификатор-типа список-описателей-структуры: список-описателей-структуры описатель-структуры описатель-структуры,список-описателей-структуры описатель-структуры: описатель описатель: константное выражение :константное-выражение инициализатор: = выражение = {список-инициализатора} = {список-инициализатора} список инициализатора: выражение список-инициализатора,список-инициализатора {список-инициализатора} имя-типа: спецификатор-типа абстрактный-описатель абстрактный-описатель: пусто {абстрактный-описатель} * абстрактный-описатель абстрактный-описатель () абстрактный-описатель [константное-выражение необ] определяющее-тип-имя: идентификатор
9.18.3. Операторы
составной-оператор: {список-описаний список-операторов необ необ} список-описаний: описание описание список-описаний список-операторов: оператор оператор список-операторов оператор: составной оператор выражение;
if (выражение) оператор if (выражение) оператор else оператор while (выражение) оператор do оператор while (выражение); for(выражение-1 ;выражение-2 ;выражение-3 ) необ необ необ оператор switch (выражение) оператор case константное-выражение : оператор default: оператор break; continue; return; return выражение; goto идентификатор; идентификатор : оператор ;
9.18.4. Внешние определения
Программа: внешнее-определение внешнее-определение программа внешнее-определение: определение-функции определение-данных определение-функции: спецификатор-типа описатель-функции тело-функции необ описатель-функции: описатель (список-параметров) необ список-параметров: идетификатор идентификатор , список-параметров тело-функции: список-описаний-типа оператор-функции оператор-функции: {список описаний список-операторов} необ определение данных: extern спецификатор типа список необ необ инициализируемых описателей ; необ static спецификатор типа список необ необ инициализируемых описателей необ;
9.18.5. Препроцессор
#define идентификатор строка-лексем #define #define идентификатор(идентификатор,...,идентификатор)стр #undef идентификатор #include "имя-файла" #include <имя-файла> #if константное-выражение #ifdef идентификатор #ifndef идентификатор #else #endif #line константа идентификатор
Последние изменения языка "C" (15 ноября 1978 г.)