Попытка понять препроцессор C

Почему эти блоки кода приводят к различным результатам?

Некоторый общий код:

#define PART1PART2 works
#define STRINGAFY0(s) #s
#define STRINGAFY1(s) STRINGAFY0(s)

случай 1:

#define GLUE(a,b,c) a##b##c  
STRINGAFY1(GLUE(PART1,PART2,*))
//yields
"PART1PART2*"

случай 2:

#define GLUE(a,b) a##b##*
STRINGAFY1(GLUE(PART1,PART2))
//yields
"works*"

случай 3:

#define GLUE(a,b) a##b
STRINGAFY1(GLUE(PART1,PART2*))
//yields
"PART1PART2*"

Я использую MSVC ++ из VS.net 2 005 sp1

Править: это в настоящее время - моя вера, что препроцессор работает как это при расширении макросов: Шаг 1: - берут тело - удаляют любой пробел вокруг ## операторов - анализируют строку, в случае, которым идентификатор найден, который соответствует названию параметра: - если это рядом с ## оператором, замените идентификатор литеральным значением параметра (т.е. строка передала в) - если это не рядом с ## оператором, выполняет этот целый процесс объяснения на значении параметра сначала, затем заменяет идентификатор тем результатом. (игнорирование stringafy единственного '#' банкомат случая) - удаляют все ## операторы

Шаг 2: - берут ту результирующую строку и анализируют его для любых макросов

теперь, от этого я полагаю, что все 3 случая должны произвести ту же самую результирующую строку:

PART1PART2*

и следовательно после шага 2, должен привести к

работы*

но самое малое должен привести к тому же самому.

6
задан Brian Tompsett - 汤莱恩 25 February 2016 в 23:29
поделиться

2 ответа

, случаи 1 и 2 не имеют определенного поведения, так как вы пытаетесь вставить * в один токен препроцессора. Согласно правилам ассоциации вашего препроцессора, он либо пытается склеить токены PART1PART2 (или просто PART2 ) и * . В вашем случае это, вероятно, не работает тихо, что является одним из возможных результатов, когда что-то не определено. Маркер PART1PART2 , за которым следует * , не будет снова рассматриваться для расширения макроса. Затем Stringfication дает результат, который вы видите.

Мой gcc ведет себя по-разному в ваших примерах:

/usr/bin/gcc -O0 -g -std=c89 -pedantic   -E test-prepro.c
test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
"works*"

Итак, чтобы подвести итог вашему случаю, у 1 есть две проблемы.

  • Вставка двух токенов, которые не дают результата в допустимом токене препроцессора.
  • порядок оценки оператора ##

В случае 3 ваш компилятор дает неверный результат. Он должен

  1. оценить аргументы для STRINGAFY1
  2. для этого он должен расширяться GLUE
  3. GLUE приводит к PART1PART2 *
  4. , который необходимо снова развернуть
  5. результат работает *
  6. , который затем передается в STRINGAFY1
3
ответ дан 17 December 2019 в 06:59
поделиться

Он делает именно то, что вы ему говорите. Первый и второй берут переданные имена символов и вставляют их вместе в новый символ. Третий берет 2 символа и вставляет их, затем вы сами помещаете * в строку (что в конечном итоге приведет к чему-то другому).

В чем именно заключается вопрос с результатами? Что ты ожидал получить? Кажется, все работает так, как я ожидал.

Тогда, конечно, возникает вопрос, почему вы вообще так играете с темным искусством манипулирования символами? :)

1
ответ дан 17 December 2019 в 06:59
поделиться