2010-12-06 2 views
14
#include <stdio.h> 
    #define f(a,b) a##b 
    #define g(a) #a 
    #define h(a) g(a) 

    int main() 
    { 
    printf("%s\n",h(f(1,2))); 
    printf("%s\n",g(f(1,2))); 
    return 0; 
    } 

Просто взглянув на программу, можно «ожидать», что выход будет таким же, как для операторов printf. Но при запуске программы вы получаете это как:# и ## в макросах

bash$ ./a.out 
12 
f(1,2) 
bash$ 

Почему это так?

ответ

18

Так как работает препроцессор.

Один '#' создаст строку из данного аргумента, независимо от того, что содержит этот аргумент, в то время как double '##' создаст новый токен, объединив аргументы.

Попробуйте просмотреть предварительно обработанный вывод (например, с gcc -E), если вы хотите лучше понять, как оцениваются макросы.

13

Ввод параметра в функционально-подобный макрос, если он не является операндом # или ##, разворачивается перед заменой его и повторным сканированием целого для дальнейшего расширения. Поскольку параметр gравен, операнд #, аргумент не разворачивается, а сразу же стягивается ("f(1,2)"). Поскольку h «с параметром не операнд # ни ##, аргумент сначала расширяется (12), а затем замещенный (g(12)), а затем повторное сканирование и дальнейшее расширение происходит ("12").

4

Ниже приведены некоторые родственные понятия к вашему вопросу:

Argument Prescan:

Макро аргументы полностью макро вспененные перед тем они подставляется в теле макрокоманды, если они не являются stringified или склейка с другими жетонами. После замещения весь макрос, , включая замещенные аргументы, сканируется для макросов расширен. В результате аргументы дважды проверяются, чтобы развернуть в них макросы .

Stringification

Когда макрос параметр используется с ведущим «#», препроцессором заменяет его буквальный текст фактического аргумента, преобразованный в в строковой константы ,

Token Pasting/Token Concatenation:

Это часто бывает полезно объединить два элемента в один, расширяя макросы. Это называется token склейка или токен конкатенация. Оператор предварительной обработки '##' выполняет склейку маркера. Когда макрос расширен, два маркера по обе стороны каждого оператора «##»: объединены в один токен, который затем заменяет оригинальные маркеры «##» и два в расширении макроса.

Так подробный процесс вашего сценария, как это:

h(f(1,2)) 
-> h(12) // f(1,2) pre-expanded since there's no # or ## in macro h 
-> g(12) // h expanded to g 
12 // g expanded 

g(f(1,2)) 
-> "f(1,2)" //f(1,2) is literally strigified because of the `#` in macro g. f(1,2) is NOT expanded at all. 
Смежные вопросы