3.1 Объектно-подобные макросы ¶
Объектно-подобный макрос — это простой идентификатор, который будет заменён фрагментом кода. Он называется объектно-подобным, потому что в коде, использующем его, он выглядит как объект данных. Чаще всего они используются для присвоения символьных имён числовым константам.
Вы создаёте макросы с помощью директивы ‘#define’. После ‘#define’ следует имя макроса, а затем последовательность токенов, для которой он должен быть сокращением, которую по-разному называют телом макроса, расширением или списком замены.
#define BUFFER_SIZE 1024
определяет макрос с именем BUFFER_SIZE как сокращение для токена 1024. Если после этой директивы ‘#define’ появляется оператор C в форме
foo = (char *) malloc (BUFFER_SIZE);
то препроцессор C распознает и расширит макрос BUFFER_SIZE. Компилятор C увидит те же токены, что и при написании
foo = (char *) malloc (1024);
По соглашению, имена макросов пишутся заглавными буквами. Программы легче читать, когда можно сразу определить, какие имена являются макросами.
Тело макроса заканчивается в конце строки ‘#define’. При необходимости определение можно продолжить на нескольких строках, используя обратную косую черту и символ новой строки. Однако при расширении макроса всё будет выведено в одной строке. Например,
#define NUMBERS 1, \
2, \
3
int x[] = { NUMBERS };
→ int x[] = { 1, 2, 3 };
Самым распространённым видимым последствием этого являются неожиданные номера строк в сообщениях об ошибках.
Нет ограничений на то, что может находиться в теле макроса, при условии, что оно разлагается на допустимые токены предварительной обработки. Скобки не обязательно должны быть сбалансированы, и тело не обязательно должно представлять собой допустимый код C. (Если это не так, то вы можете получить сообщения об ошибках от компилятора C при использовании макроса.)
Препроцессор C сканирует вашу программу последовательно. Определения макросов вступают в силу в том месте, где вы их пишете. Поэтому следующий ввод для препроцессора C
foo = X; #define X 4 bar = X;
производит
foo = X; bar = 4;
Когда препроцессор расширяет имя макроса, расширение макроса заменяет вызов макроса, а затем расширение проверяется на наличие других макросов для расширения. Например,
#define TABLESIZE BUFSIZE
#define BUFSIZE 1024
TABLESIZE
→ BUFSIZE
→ 1024TABLESIZE сначала расширяется, чтобы получить BUFSIZE, затем этот макрос расширяется, чтобы получить окончательный результат, 1024.
Обратите внимание, что BUFSIZE не было определено, когда TABLESIZE было определено. ‘#define’ для TABLESIZE использует именно то расширение, которое вы указываете — в данном случае, BUFSIZE—и не проверяет, содержит ли оно также имена макросов. Только при использовании TABLESIZE результат его расширения сканируется на наличие других имён макросов.
Это имеет значение, если вы измените определение BUFSIZE в какой-то момент исходного файла. TABLESIZE, определённый, как показано, всегда будет расширяться, используя определение BUFSIZE, которое в данный момент действует:
#define BUFSIZE 1020 #define TABLESIZE BUFSIZE #undef BUFSIZE #define BUFSIZE 37
Теперь TABLESIZE расширяется (в два этапа) до 37.
Если расширение макроса содержит собственное имя, либо напрямую, либо через промежуточные макросы, оно не расширяется повторно при проверке расширения на наличие других макросов. Это предотвращает бесконечную рекурсию. См. Самоссылочные макросы для точных подробностей.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-11.4.0/cpp/Object-like-Macros.html