在为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)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);
}
}
}
由于代码不是特定于窗口的,因此每个256
值都应转换为PATH_MAX
。
我知道在引用字符串中扩展宏是不可能的,但字符串连接是微不足道的:
#define STR "string"
size_t len=strlen("part"STR"part 2");
然而,像:
"%."PATH_MAX".db"
不应该有效,因为PATH_MAX
扩展为整数,而不是字符串
那么有没有办法在不调用将整数转换为C字符串的函数的情况下执行此操作?
答案 0 :(得分:3)
执行此操作的正确方法是在格式字符串中使用*
,这将使其从参数列表中获取值。例如:
printf("%.*s\n", 3, "abcde");
这相当于:
printf("%.3s\n", "abcde");
通过这种方式,您可以使用PATH_MAX
或任何其他值来控制格式,而无需担心它们是如何定义的(例如,它们是否包含括号或加法运算符等)。
答案 1 :(得分:1)
您可以使用#
运算符对宏参数进行字符串化。但是您需要间接宏调用来扩展参数:
#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字节的分配,但是使用像snprintf
这样的检查长度的sprintf会更好。这将具有不需要宏观游戏的额外优势。