宏将先前的宏标识符字符串化而不是替换它

时间:2017-02-07 22:39:09

标签: c macros stringification

为什么inner_LOAD_ATOM(buffer, ATOM_MAX)已转换为scanf("%" "ATOM_MAX" "s", x)但包装版本不是?我希望ATOM_MAX(标识符)在被"传递之前被替换为10#34;到inner_LOAD_ATOMLOAD_LINE并使包装无用。更详细的回答为什么包装是必要的将非常感激。

#include <stdio.h>

#define ATOM_MAX 10
#define inner_LOAD_ATOM(x, y) scanf("%" #y "s", x)      /* inner part */
#define LOAD_ATOM(x, y) inner_LOAD_ATOM(x, y)           /* wrapper of inner_LOAD_ATOM */


int main(void)
{
    char buffer[ATOM_MAX] = {0, };

    /* wrapped works fine */
    LOAD_ATOM(buffer, ATOM_MAX);        

    /* [Warning] unknown conversion
    type character 'A' in format [-Wformat=] */
    inner_LOAD_ATOM(buffer, ATOM_MAX);

    printf("%s\n", buffer);


    return 0;
}

2 个答案:

答案 0 :(得分:2)

重要的是要理解类似函数的宏不像C函数那样工作。 (几乎)没有宏调用堆栈或从一个宏到另一个宏的转发参数的意义。相反,宏扩展以迭代方式进行 - 宏被其扩展替换,然后重新扫描扩展以进一步扩展宏。

类函数宏的参数在插入宏的替换文本之前完全是宏扩展的,除了,它们是字符串化(#)或令牌粘贴的操作数( ##)运营商。因此,如果您直接调用inner_LOAD_ATOM(buffer, ATOM_MAX),则在应用ATOM_MAX运算符之前不会展开#

另一方面,当您调用LOAD_ATOM(buffer, ATOM_MAX)时,ATOM_MAX宏会在展开LOAD_ATOM()之前展开。 inner_LOAD_ATOM()在此时没有考虑因素 - 它只是外部宏替换文本的一部分,直到LOAD_ATOM()的扩展被重新扫描以进行进一步的宏扩展。

答案 1 :(得分:1)

因为第一次传递#y将被#ATOM_MAX替换并且已经过字符串化。所以它不会在第二次传球时得到扩展。让我们手动运行它:

第一遍:

int main(void)
{
    char buffer[10] = {0, };

    /* wrapped works fine */
    inner_LOAD_ATOM(buffer, 10); // <-- Note - here it ATOM_MAX was expanded in the first pass       

    /* [Warning] unknown conversion
    type character 'A' in format [-Wformat=] */
    scanf("%" "ATOM_MAX" "s", buffer); 

    printf("%s\n", buffer);


    return 0;
}

第二遍:

int main(void)
{
    char buffer[10] = {0, };

    /* wrapped works fine */
    scanf("%" "10" "s", buffer);        

    /* [Warning] unknown conversion
    type character 'A' in format [-Wformat=] */
    scanf("%" "ATOM_MAX" "s", buffer);   // <----- Not expanded as is interpreted as string

    printf("%s\n", buffer);


    return 0;
}