Поделиться через


Директива #define (C/C++)

#define создает макрос, который является связью идентификатора или параметризованного идентификатора со строкой токена. После определения макроса компилятор может подставить строку токена для каждого обнаруженного идентификатора в исходном файле.

Синтаксис

#define маркер-строкаидентификатора
#define идентификатор (идентификаторopt, ... , идентификатор opt ) токен-строка

Замечания

Директива #define приводит компилятору заменить строку маркера для каждого вхождения идентификатора в исходном файле. Идентификатор заменяется только в том случае, если он формирует маркер. То есть идентификатор не заменяется, если он отображается в комментарии, в строке или в составе более длинного идентификатора. Дополнительные сведения см. в разделе "Токены".

Аргумент строки токена состоит из ряда маркеров, таких как ключевые слова, константы или полные операторы. Один или несколько символов пробелов должны отделять строку маркера от идентификатора. Эти пробелы не считаются частью замененного текста, как и все остальные пробелы, следующие за последним токеном текста.

Без #define строки маркера удаляется вхождения идентификатора из исходного файла. Идентификатор остается определенным и может быть проверен с помощью #if defined директив и #ifdef инструкций.

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

Имена формальных параметров отображаются в строке токена, чтобы пометить расположения, в которых заменяются фактические значения. Каждое имя параметра может отображаться несколько раз в строке маркера, и имена могут отображаться в любом порядке. Число аргументов в вызове должно соответствовать числу параметров в определении макроса. Надлежащее использование скобок обеспечит правильную обработку сложных фактических аргументов.

Формальные параметры в списке разделяются запятыми. Все имена в списке должны быть уникальными, и список должен быть заключен в скобки. Пробелы не могут разделять идентификатор и открываемую скобку. Используйте объединение строк — поместите обратную косую косую черту (\) непосредственно перед новым символом — для длинных директив в нескольких исходных строках. Область формального имени параметра расширяется на новую строку, которая заканчивается строкой маркера.

Если макрос определен во второй форме синтаксиса, последующие текстовые экземпляры, за которыми находится список аргументов, указывают на вызов макроса. Фактические аргументы, следующие за экземпляром идентификатора в исходном файле, соответствуют соответствующим формальным параметрам в определении макроса. Каждый формальный параметр в строке токена, который не предшествует строковой (), charizing (#@#), или оператор вставки маркеров (##) или не следует ## оператору, заменяется соответствующим фактическим аргументом. Перед заменой директивой формального параметра все макросы в фактическом аргументе разворачиваются. (Операторы описаны в разделе Операторы препроцессора.)

В следующих примерах макросов с аргументами показана вторая форма синтаксиса #define :

// Macro to define cursor lines
#define CURSOR(top, bottom) (((top) << 8) | (bottom))

// Macro to get a random integer with a specified range
#define getrandom(min, max) \
    ((rand()%(int)(((max) + 1)-(min)))+ (min))

Аргументы с побочными эффектами иногда приводят к тому, что макросы дают непредвиденные результаты. Заданный формальный параметр может отображаться несколько раз в строке токена. Если этот формальный параметр заменяется выражением с побочными эффектами, выражение с такими эффектами может вычисляться несколько раз. (См. примеры в разделе Оператор вставки токенов (#).)

Директива #undef приводит к тому, что определение препроцессора идентификатора забывается. Дополнительные сведения см . в директиве #undef.

Если имя определяемого макроса происходит в строке маркера (даже в результате другого расширения макроса), он не расширяется.

Второй #define для макроса с тем же именем создает предупреждение, если только вторая последовательность маркеров не идентична первой.

Блок, относящийся только к системам Майкрософт

Если новое определение синтаксически совпадает с исходным, Microsoft C и C++ позволяют переопределить макрос. Другими словами, два определения могут иметь разные имена параметров. Это поведение отличается от ANSI C, которое требует, чтобы два определения были лексически идентичны.

Например, следующие два макроса идентичны, за исключением имен параметров. ANSI C не разрешает такое переопределение, но Microsoft C/C++ компилирует его без ошибок.

#define multiply( f1, f2 ) ( f1 * f2 )
#define multiply( a1, a2 ) ( a1 * a2 )

С другой стороны, следующие два макроса неидентичны и приводят к выдаче предупреждения в Microsoft C и C++.

#define multiply( f1, f2 ) ( f1 * f2 )
#define multiply( a1, a2 ) ( b1 * b2 )

Завершение блока, относящегося только к системам Майкрософт

В этом примере показана директива #define :

#define WIDTH       80
#define LENGTH      ( WIDTH + 10 )

Первый оператор определяет идентификатор WIDTH как целочисленную константу 80, а затем LENGTH задается в виде WIDTH и целочисленной константы 10. Каждое вхождение LENGTH заменяется на (WIDTH + 10). В свою очередь, каждое вхождение WIDTH + 10 заменяется выражением (80 + 10). Скобки вокруг WIDTH + 10 имеют важное значение, поскольку управляют интерпретацией в операторах, например в следующем:

var = LENGTH * 20;

После этапа предварительной обработки этот оператор принимает следующий вид:

var = ( 80 + 10 ) * 20;

что равно 1800. Без скобок результат будет следующим:

var = 80 + 10 * 20;

значение 280.

Блок, относящийся только к системам Майкрософт

Определение макросов и констант с параметром компилятора /D имеет тот же эффект, что и при использовании директивы предварительной обработки #define в начале файла. С помощью параметра /D можно определить до 30 макросов.

Завершение блока, относящегося только к системам Майкрософт

См. также

Директивы препроцессора