Во время раскрытия макроса C существует ли особый случай для макросов, который расширится до "/ *"? - PullRequest
13 голосов
/ 12 ноября 2010

Вот соответствующий пример. Это, очевидно, неверно 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)

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

gcc -std=c99 -E macrotest.c

Это дает:

(...)

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

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

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

Ответы [ 2 ]

15 голосов
/ 12 ноября 2010

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

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

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

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

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

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

...

P(foo,bar)   

приводит к токену foobar

P(+,+)

приводит к токену ++, но

P(/,*)       

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

5 голосов
/ 12 ноября 2010

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

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

Это происходит раньше:

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

...