Подтвердить что ты не робот

Использование # в макросе

Пожалуйста, объясните код

#include <stdio.h>
#define A(a,b) a##b
#define B(a) #a
#define C(a) B(a)

main()
{
 printf("%s\n",C(A(1,2)));
 printf("%s\n",B(A(1,2)));
}

Выход

12

А (1,2)

Я не понимаю, как первый printf оценивает до 12? Разве это не похоже на второе, так как макрос макроса - это просто оболочка для макроса B?

4b9b3361

Ответ 1

Путаница здесь происходит из простого правила.

При оценке макроса предварительный процессор сначала разрешает макросы в аргументах, переданных макросу. Однако в качестве частного случая, если аргумент имеет право на # или рядом с ##, он не разрешает макросы внутри таких аргументов. Таковы правила.

Ваш первый случай

C(A(1,2))

В предварительном процессоре сначала применяется макрос C(a), который определяется как B(a). Там нет # или ## рядом с аргументом в определении (ни один из них в B(a) вообще), поэтому предварительный процессор должен разрешить макросы в аргументе:

A(1,2)

Определение A(a,b) - это a##b, которое оценивается как 12.

После вычисления макросов в аргументах макроса C(a) макрос C становится:

C(12)

Препроцессор теперь решает макрос C(a), который согласно его определению становится

B(12)

Как только это будет сделано, предварительный процессор снова проверит макросы внутри результата и применит макрос B(a), поэтому результат будет

"12"

Второй случай

B(A(1,2))

Как и в первом случае, предварительный процессор сначала применяет макрос B(a). Но на этот раз определение макроса таково, что аргументу предшествует #. Поэтому применяется специальное правило, и макросы внутри аргумента оцениваются не. Следовательно, результат немедленно становится:

"A(1,2)"

Препроцессор снова повторяет результат, пытаясь найти больше макросов для расширения, но теперь все это часть строки, а макросы не расширяются в строках. Итак, конечный результат:

"A(1,2)"

Ответ 2

Как упоминалось в Википедии в C-препроцессор:

Оператор ## (известный как "Оператор вставки тонера" ) конкатенатирует два токена в один токен.

Оператор # (известный как "оператор стриминга" ) преобразует токена в строку, избегая любых кавычек или обратных косых черт соответственно.

Если вы хотите ограничить расширение аргумента макроса, у вас есть для использования двух уровней макросов:

Вы не можете комбинировать аргумент макроса с дополнительным текстом и строчить все это вместе. Однако вы можете написать ряд соседних строк константы и строгие аргументы: компилятор C затем объединяет все соседние строковые константы в одну длинную строку.

#define xstr(s) str(s)
#define str(s) #s
#define foo 4

str (foo)  // outputs "foo"
xstr (foo) // outputs "4"

Кроме того, из C-FAQ Вопрос 11.17:

Оказывается, что определение # говорит, что оно должно немедленно приведите аргумент макроса, не расширяя его (если аргумент является именем другого макроса).

Итак, аналогично, следуя этим строкам:

you're doing C(A(1,2)), 
which would roll to C(12), // since no #, so inner argument is expanded
and then to B(12)
// [since you've done two levels of macros in the code:
// 1. from C() to B(), and then, 2. B() to #a]
= 12 . 

В то время как в первом случае только 1 уровень строкообразования явно выполняется в соответствии с определением B (a) (поскольку он немедленно стягивается из-за #)

macro-replacement of B(A(1,2)) 
= stringification of A(1,2) 
= A(1,2).

Ответ 3

C препроцессор имеет два оператора # и ##. Оператор # превращает аргумент функции, такой как macro, в строку с кавычками, где оператор ## объединяет два идентификатора.

#define A(a,b) a##b will concatenate a with b returning ab as string.
so A(1,2) will return 12
#define B(a) #a  will return a as string
#define C(a) B(a) will call previous one and return a as string.
so C(A(1,2)) = C(12) = B(12) = 12 (as string)
B(A(1,2)) = A(1,2) because A(1,2) is taken as an argument and returned as string A(1,2) 

Ответ 4

В функционально-подобных макросах используются два оператора:

  • ## заставляет макрос конкатенировать два параметра.
  • # заставляет вход эффективно преобразовываться в строковый литерал.

В A(a,b) ## происходит слияние с b. В B(a), # эффективно создает строковый литерал из ввода. Таким образом, разложение выполняется следующим образом:

C(A(1,2)) -> C(12) -> B(12) -> "12"
B(A(1,2)) -> "A(1,2)"

Поскольку для C(A(1,2)) часть A(1,2) оценивается сначала, чтобы она превратилась в 12, два оператора не равны, как они выглядели бы.

Подробнее об этом можно узнать в cppreference.