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

Macro stringifies a previous macros identifier instead of its replacement

为什么 inner_LOAD_ATOM(buffer, ATOM_MAX) 转换为 scanf("%" "ATOM_MAX" "s", x) 而包装版本却没有?我希望 ATOM_MAX(identifier) 在 "passed" 到 inner_LOAD_ATOMLOAD_LINE 之前被 10 替换并使包装器无用。非常感谢为什么需要包装器的更详细的答案。

#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;
}

因为在第一次传递时 #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;
}

了解 function-like 宏不像 C 函数那样工作很重要。 (几乎)没有宏调用堆栈或将参数从一个宏转发到另一个宏的感觉。相反,宏扩展迭代地进行——宏被它的扩展替换,然后重新扫描扩展以进一步扩展宏。

一个 function-like 宏的参数在被插入到宏的替换文本之前完全被宏展开, 除了 它们是字符串化的操作数(#) 或 token-pasting (##) 运算符。因此,如果您直接调用 inner_LOAD_ATOM(buffer, ATOM_MAX),则在应用 # 运算符之前不会展开 ATOM_MAX

另一方面,当您调用 LOAD_ATOM(buffer, ATOM_MAX) 时,ATOM_MAX 宏会先于 LOAD_ATOM() 展开。 inner_LOAD_ATOM() 在那一点上没有考虑——它只是外部宏替换文本的一部分,直到 LOAD_ATOM() 的扩展为 re-scanned 以进行进一步的宏扩展。