При расширении макросов C существует специальный случай для макросов, который будет расширяться до "/*"?

Вот пример. Это явно недействительно C, но я просто имею дело с препроцессором здесь, поэтому код на самом деле не нужно компилировать.

#define IDENTITY(x) x
#define PREPEND_ASTERISK(x) *x
#define PREPEND_SLASH(x) /x

IDENTITY(literal)
PREPEND_ASTERISK(literal)
PREPEND_SLASH(literal)
IDENTITY(*pointer)
PREPEND_ASTERISK(*pointer)
PREPEND_SLASH(*pointer)

Запуск gc-препроцессора на нем:

gcc -std=c99 -E macrotest.c

Это дает:

(...)

literal
*literal
/literal
*pointer
**pointer
/ *pointer

Обратите внимание на дополнительное пространство в последней строке.

Это похоже на функцию, позволяющую предотвратить расширение макросов до "/*", что, я уверен, имеет благие намерения. Но с первого взгляда я не мог найти ничего подобного этому поведению в стандарте C99. Опять же, я неопытен в C. Может кто-то пролить свет на это? Где это указано? Я бы предположил, что компилятор, придерживающийся C99, не должен просто вставлять лишние пробелы во время расширения макросов только потому, что он, вероятно, предотвратит ошибки программирования.

Ответы

Ответ 1

Исходный код уже обозначен перед обработкой CPP.

Итак, у вас есть токен / и *, который не будет объединен неявно с токеном /* "(поскольку/* на самом деле не является токеном препроцессора, я положил его в" ").

Если вы используете -E для вывода предварительно обработанного источника, CPP необходимо вставить пространство, чтобы избежать /*, прочитанного последующим проходом компилятора.

Такая же функция предотвращает два, например, + знаки из разных макросов объединяются в токен ++ на выходе.

Единственный способ действительно вставить два токена препроцессора вместе с оператором ##:

#define P(x,y) x##y

...

P(foo,bar)   

выводит токен foobar

P(+,+)

выводит токен ++, но

P(/,*)       

недействителен, поскольку /* не является допустимым токеном препроцессора.

Ответ 2

Поведение препроцессора стандартизировано. В сводке http://en.wikipedia.org/wiki/C_preprocessor результаты, которые вы наблюдаете, являются результатом:

"3: Tokenization - препроцессор разбивает результат на токены препроцессора и пробелы. Он заменяет комментарии пробелами".

Это происходит до:

"4: Расширение макросов и обработка директивы".