Определение макроса длится (независимо от структуры блока) до тех пор, пока#undef не встретится соответствующая директива или (если не встретится ни одна) до конца единицы трансляции. Макроопределения не имеют значения после фазы перевода 4.
Директива предварительной обработки формы
# undef identifier new-line
заставляет указанный идентификатор больше не определяться как имя макроса. Он игнорируется, если указанный идентификатор в настоящее время не определен как имя макроса.
[ Example: Самым простым способом использования этой возможности является определение «константы манифеста», как в
#define TABSIZE 100 int table[TABSIZE];
— end example ]
[ Example: Следующее определяет макрос, подобный функции, значение которого является максимальным из его аргументов. Он имеет преимущества работы с любыми совместимыми типами аргументов и генерации встроенного кода без накладных расходов на вызов функции. У него есть недостатки, заключающиеся в том, что он оценивает один или другой его аргумент второй раз (включая побочные эффекты) и генерирует больше кода, чем функция, если вызывается несколько раз. Он также не может получить свой адрес, поскольку у него его нет.
#define max(a, b) ((a) > (b) ? (a) : (b))
Скобки обеспечивают правильную привязку аргументов и результирующего выражения. ] — end example
[ Example: Чтобы проиллюстрировать правила переопределения и пересмотра, последовательность
#define x 3 #define f(a) f(x * (a)) #undef x #define x 2 #define g f #define z z[0] #define h g(~ #define m(a) a(w) #define w 0,1 #define t(a) a #define p() int #define q(x) x #define r(x,y) x ## y #define str(x) # x f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); g(x+(3,4)-w) | h 5) & m (f)^m(m); p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; char c[2][6] = { str(hello), str() };
приводит к
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); int i[] = { 1, 23, 4, 5, }; char c[2][6] = { "hello", "" };
— end example ]
[ Example: Чтобы проиллюстрировать правила создания символьных строковых литералов и конкатенации токенов, последовательность
#define str(s) # s
#define xstr(s) str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
x ## s, x ## t)
#define INCFILE(n) vers ## n
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"
debug(1, 2);
fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away
== 0) str(: @\n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)
приводит к
printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
#include "vers2.h" (after macro replacement, before file access)
"hello";
"hello" ", world"
или после конкатенации символьных строковых литералов,
printf("x1= %d, x2= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0: @\n", s);
#include "vers2.h" (after macro replacement, before file access)
"hello";
"hello, world"
Пространство вокруг # и ## лексемы в определении макроса не является обязательным. ] — end example
[ Example: Чтобы проиллюстрировать правила для маркеров предварительной обработки меток, последовательность
#define t(x,y,z) x ## y ## z int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) };
приводит к
int j[] = { 123, 45, 67, 89, 10, 11, 12, };
— end example ]
[ Example: Чтобы продемонстрировать правила переопределения, допустима следующая последовательность.
#define OBJ_LIKE (1-1) #define OBJ_LIKE /* white space */ (1-1) /* other */ #define FUNC_LIKE(a) ( a ) #define FUNC_LIKE( a )( /* note the white space */ \ a /* other stuff on this line */ )
Но следующие переопределения недействительны:
#define OBJ_LIKE (0) // different token sequence #define OBJ_LIKE (1 - 1) // different white space #define FUNC_LIKE(b) ( a ) // different parameter usage #define FUNC_LIKE(b) ( b ) // different parameter spelling
— end example ]
[ Example: Наконец, чтобы показать возможности макроса списка переменных аргументов:
#define debug(...) fprintf(stderr, __VA_ARGS__) #define showlist(...) puts(#__VA_ARGS__) #define report(test, ...) ((test) ? puts(#test) : printf(__VA_ARGS__)) debug("Flag"); debug("X = %d\n", x); showlist(The first, second, and third items.); report(x>y, "x is %d but y is %d", x, y);
приводит к
fprintf(stderr, "Flag"); fprintf(stderr, "X = %d\n", x); puts("The first, second, and third items."); ((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y));
— end example ]