为什么inner_LOAD_ATOM(buffer, ATOM_MAX)
已转换为scanf("%" "ATOM_MAX" "s", x)
但包装版本不是?我希望ATOM_MAX(标识符)在被"传递之前被替换为10#34;到inner_LOAD_ATOM
或LOAD_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;
}
答案 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;
}