C++
Шрифт:
11. Командные строки компилятора
Компилятор содержит препроцессор, способный выполнять макроподстановки, условную компиляцию и включение именованных файлов. Строки, начинающиеся с #, относятся к препроцессору. Эти строки имеют независимый от остального языка синтаксис; они могут появляться в любом месте и оказывать влияние, котрое распространяется (независимо от области видимости) до конца файла исходной программы.
Учтите, что определения const и inline дают альтернативы для большинства использований #define.
11.1 Замена лексем
Командная строка компилятора вида
#define идентификатор строка_лексем
Строка вида
#define идентификатор( идентификатор , ... , идентификатор) строка_лексем
где нет пробела между первым идентификатором и (, явлется макроопределением с параметрами. Последующие вхождения первого идентификатора с идущими за ним (, последователностью символов, разграниченной запятыми, и ), заменяются строкой символов, заданной в определении. Каждое местоположние идентификатора, замеченного в списке параметров определния, заменяется соответствующей строкой из вызова. Фактичекими параметрами вызова являются строки символов, разделенные запятыми; однако запятые в строке, заключенной в кавычки, или в круглых скобках не являются разделителями параметров. Число формальных и фактических параметров должно совпадать. Строки и символьные константы в символьной строке сканируются в писках формальных параметров, но строки и символьные константы в остальной программе не сканируются в поисках определенных
(с помощью define) идентификаторов.
В обоих случаях строка замещения еще раз сканируется в поисках других определнных идентификаторов. В обоих случаях длинное определение может быть продолжено на другой строке с помощью записи \ в конце продолжаемой строки.
Командная строка вида
#undef идентификатор
влечет отмену препроцессорного определения идентификатра.
11.2 Включение файлов
Командная строка компилятора вида
#include «имя_файла»
вызывает замену этой строки полным содержимым файла имя_ файла. Сначала именованный файл ищется в директории первончального исходного файла, а затем в стандартных или заданных местах. Альтернативный вариант, командная строка вида
#include «имя_файла»
производит поиск только в стандартном или заданном мете, и не ищет в директории исходного файла. (То, как эти мета задаются, не является частью языка.) Включения с помощью #include могут быть вложенными.
11.3 Условная компиляция
Командная строка компилятора вида
#if выражение
проверяет, является ли результатом вычисления выражения не-ноль. Выражение должно быть константным выражением, котрые обсуждаются в #12. Кроме обычных операций С++ может ипользоваться унарная операция defined. При применении к идетификатору она дает значение не-ноль, если этот идентификатор был ранее определен с помощью #define и после этого не было отмены определения с помощью #undef; иначе ее значение 0. Командная строка вида
#ifdef идентификатор
проверяет, определен ли идентификатор в препроцессоре в данный момент; то есть, был ли он объектом командной строки # define. Командная строка вида
#ifndef идентификатор
проверяет, является ли идентификатор неопределенным в препроцессоре в данный момент.
После каждого из трех видов может стоять произвольное количество строк, возможно, содержащих командную строку
#else
и далее до командной строки
#endif
Если проверенное условие истинно, то все строки между #else и #endif игнорируются. Если проверенное условие
ложно, то все строки между проверкой и #else или, в случае отсуттвия #else, #endif, игнорируются.Эти конструкции могут быть вложенными.
11.4 Управление строкой
Для помощи другим препроцессорам, генерирующим программы на С++, строка вида
#line константа «имя_файла»
заставляет компилятор считать, например, в целях дианостики ошибок, что константа задает номер следущей строки исходного файла, и текущий входной файл именуется идентификтором. Если идентификатор отсутствует, то запомненное имя файла не изменяется.
12. Константные выражения
В нескольких местах С++ требует выражения, вычисление которых дает константу: в качестве границ массива (#8.4), в case выражениях (#9.7), в качестве значений параметров фунции по умолчанию (#8.3), и в инициализаторах (#8.6). В первом случае выражение может включать только целые константы, сивольные константы, константы перечислений, значения несостаных const, инициализированных константными выражениями, и sizeof выражения, возможно, связанные бинарными операциями
+ – * / % amp; ! ^ «„ “» == != « » «= »= amp; amp; !!
или унарными операциями
+ – ~ !
или тернарной операцией
?:
Скобки могут использоваться для группирования, но не для вызова функций.
Во всех остальных случаях константное выражение может также содержать унарную операцию amp;, примененную к внешним или статическим объектам, или к внешним или статическим массивам, индексированным константным выражением. Унарная операция amp; может также быть применена неявно с помощью употребления ниндексированных массивов и функций. Основное правило состоит в том, что инициализаторы должны при вычислении давать контанту или адрес ранее описанного внешнего или статического обйекта плюс или минус константа.
Меньшая широта допустима для константных выражений после #if: недопустимы имена, описанные const, sizeof выражения и перечислимые константы.
13. Соображения мобильности
Определенные части С++ являются машинно зависимыми по своей сути. Следующий ниже список мест возможных затруднений не претендует на полноту, но может указать на основные из них.
Как показала практика, характеристики аппаратуры в читом виде, такие, как размер слова, свойства плавающей арифмтики и целого деления, не создают особых проблем. Другие апаратные аспекты отражаются на различных программных разработках. Некоторые из них, особенно знаковое расширение (преобразование отрицательного символа в отрицательное целое) и порядок расположения байтов в слове, являются досадными пмехами, за которыми надо тщательно следить. Большинство отальных являются всего лишь мелкими сложностями.
Число регистровых переменных, которые фактически могут быть помещены в регистры, различается от машины к машине, как и множество дейсвующих типов. Тем не менее, все компиляторы на «своей» машине все делают правильно; избыточные или ндействующие описания register игнорируются.
В языке неопределен порядок вычисления параметров фунции. На некоторых машинах он слева направо, а на остальных справа налево. Порядок появления побочных эффектов также ндетерминирован.
Поскольку символьные константы в действительности явлются объектами типа int, то могут быть допустимы многосивольные константы. Однако конкретная реализация очень сильно зависит от машины, поскольку порядок, в котором символы приваиваются слову, различается от машины к машине.