Вопрос

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

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

#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 2005 SP1.

Редактировать:в настоящее время я считаю, что препроцессор работает следующим образом при расширении макросов:Шаг 1:- Возьмите тело - удалите любое пробелы вокруг операторов ## - проанализируйте строку, в случае, когда найден идентификатор, который соответствует имени параметра:-если он находится рядом с оператором ##, замените идентификатор буквальным значением параметра (т. е.Строка прошел в) -Если она не находится рядом с оператором ##, запустите весь этот процесс объяснения на значении параметра сначала, а затем замените идентификатор этим результатом.(игнорируя Stringafy Single '#' Case ATM) -Ремоурация All ## Operators

Шаг 2:- возьмите полученную строку и проанализируйте ее на наличие макросов

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

ЧАСТЬ1ЧАСТЬ2*

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

работает*

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

Это было полезно?

Решение

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

Мой 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. результат works*
  6. который затем передаетсяSTRINGAFY1

Другие советы

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top