C 展开带引号字符串内的整数宏
在为exim做贡献时,我看到了许多硬编码的值:C 展开带引号字符串内的整数宏,c,macros,c-preprocessor,c-strings,exim,C,Macros,C Preprocessor,C Strings,Exim,在为exim做贡献时,我看到了许多硬编码的值: uschar filebuffer[256]; (void)sprintf(CS filebuffer, "%.256s.db", filename); rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups, "dbm", errmsg); if (rc < 0) /* stat() failed */ { (void)spr
uschar filebuffer[256];
(void)sprintf(CS filebuffer, "%.256s.db", filename);
rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
"dbm", errmsg);
if (rc < 0) /* stat() failed */
{
(void)sprintf(CS filebuffer, "%.256s.dir", filename);
rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
"dbm", errmsg);
if (rc == 0) /* x.dir was OK */
{
(void)sprintf(CS filebuffer, "%.256s.pag", filename);
rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
"dbm", errmsg);
}
}
}
但是,像这样的事情:
"%."PATH_MAX".db"
不应该工作,因为PATH\u MAX
扩展为整数,而不是字符串。那么,有没有一种方法可以在不调用将整数转换为C字符串的函数的情况下实现这一点 ? 您可以使用
#
运算符对宏参数进行字符串化。但您需要一个间接宏调用来扩展参数:
#define Q(x) Q_(x)
#define Q_(x) #x
所以你可以这样做:
char filebuffer[PATH_MAX + 10];
sprintf(filebuffer, "%." Q(PATH_MAX)"s.db", filename);
现有代码将字符串sibstitution限制为256个字符,但随后添加了一个文件扩展名(和NUL终止符),当长度接近256时,这将导致缓冲区溢出。我在上面使用了任意10字节的过度分配,但最好使用检查长度的sprintf,如
snprintf
。这样做的另一个好处是不需要宏游戏。正确的方法是在格式字符串中使用*
,这将使它从参数列表中获取值。例如:
printf("%.*s\n", 3, "abcde");
这相当于:
printf("%.3s\n", "abcde");
这样,您就可以使用
PATH\u MAX
或任何其他值来控制格式,而不必担心它们是如何定义的(例如,它们是否包含括号或加法运算符等)为什么您要强制执行函数调用而不是分析它们的返回值?@iharob:因为我没有编写这段代码。请阅读第一行,这是我没有修改的exim代码的一部分。很多事情都做得不对:大多数代码根本没有缩进,甚至还有对malloc()
调用的返回值没有被选中。@user2284570不,不会<代码>#字符串化附加到它的值。按照您显示的方式执行将生成“%.PATH\u MAX.db”
,而不是“%.256.db”
。您需要将PATH\u MAX
传递给宏,以将其计算为其值,然后将该值字符串化。@RemyLebeau:实际上,OP在该注释中所写的内容只会字符串化(
(假设它出现在宏替换中,因为至少在理论上,#是宏替换之外的一个错误。这应该是公认的答案,因为它像原始的一样使用编译时处理。如果您只是想再详细说明一下。@Olaf您是在开玩笑吧?如果PATH_MAX
被定义为(2*512)该怎么办
?那么这个解决方案永远都不可能奏效。这是一个错误的方法。@汤姆:我同意有比依赖宏作为简单数字更好的解决方案。但是,我不认为长度插值真的更好,因为它取决于手动计算格式字符串需要多少额外字符;总的来说,snprintf是一种解决方案,即使你必须为那些太旧而缺少它的系统找到一个实现,而这些系统已经没有那么多了。对不起,必须进行虚拟编辑才能删除DV。你真的有道理
printf("%.3s\n", "abcde");