我想获得以下代码片段:
#define READIN(a, b) if(scanf('"#%d"', '"&a"') != 1) { printf("ERROR"); return EXIT_FAILURE; }
int main(void)
{
unsigned int stack_size;
printf("Type in size: ");
READIN(d, stack_size);
}
我不明白,如何使用#
运算符的指令。我想多次使用scanf
打印ERROR等,但"'"#%d"'
& '"&a"'"
我觉得完全错了。有没有办法让它运行?我认为宏是最好的解决方案吗?
答案 0 :(得分:4)
您错误地包含了您的宏参数,它应该如下所示:
#define READIN(a, b) if(scanf("%"#a, &b) != 1) { printf("ERROR"); return EXIT_FAILURE; }
你使用stringify运算符也是不正确的,它必须直接在参数名前加前缀。
简而言之,请使用"%"#a
,而不是'"#%d"'
和&b
,而不是'"&a"'
。
作为旁注,对于像这样的longish宏,它有助于使用\
使它们成为多行,这使它们可读:
#define READIN(a, b) \
if(scanf("%"#a, &b) != 1) \
{ \
printf("ERROR"); \
return EXIT_FAILURE; \
}
当做这样的事情时,最好使用一个函数,这应该是有效的:
inline int readIn(char* szFormat, void* pDst)
{
if(scanf(szFormat,pDst) != 1)
{
puts("Error");
return 0;
}
return 1;
}
调用它就像这样:
if(!readIn("%d",&stack_size))
return EXIT_FAILURE;
答案 1 :(得分:3)
scanf(3)
将const char *
作为第一个参数。您正在传递'"..."'
,这不是C“字符串”。 C字符串使用"
双引号编写。 '
单引号适用于单个字符:'a'
或'\n'
等。
在C预处理器宏中放置return
语句通常被认为是非常糟糕的形式。在将格式化数据存储到文件或内核接口的数据并从文件或内核接口读取数据时,我已经看到goto error;
在预处理器宏中编码,然后才会出现重复的错误处理代码,但这些都是特殊情况。您会在六个月后厌恶调试。相信我。不要在C预处理器宏中隐藏goto
,return
,break
,continue
。只要它完全包含在宏中,if
就没问题。
另外,请养成这样写printf(3)
语句的习惯:
printf("%s", "ERROR");
Format string vulnerabilities非常容易写。您的代码现在不包含任何此类漏洞,但相信我,将来在某些点上这些字符串不可避免地被修改为包含一些用户提供的内容,并且现在放入一个显式格式字符串 将来有助于防止这些问题。如果你看到这个,至少你将来会考虑它。
是considered polite to wrap your multi-line macros in do { } while (0)
blocks。
最后,stringification没有完全正确地完成;试试这个:
#define READIN(A, B) do { if (scanf("%" #A, B) != 1) { \
/* error handling */ \
} else { \
/* success case */ \
} } while(0)
编辑:我觉得我应该重新审核akappa's advice:改用函数。您可以获得更好的类型检查,在出现问题时更好地回溯,并且更容易使用。功能很好。