19 Preprocessing directives [cpp]

19.3 Macro replacement [cpp.replace]

19.3.5 Scope of macro definitions [cpp.scope]

Определение макроса длится (независимо от структуры блока) до тех пор, пока#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]