Использование # в макросе
Пожалуйста, объясните код
#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?
Ответы
Ответ 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.