在引用的字符串中扩展整数宏
Expand integer macro inside quoted string
在为 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);
}
}
}
由于代码不是 windows 具体的,每个 256
值都应转换为 PATH_MAX
。
我知道在带引号的字符串中扩展宏是不可能的,但是字符串连接很简单:
#define STR "string"
size_t len=strlen("part"STR"part 2");
但是,诸如:
"%."PATH_MAX".db"
应该不起作用,因为PATH_MAX
扩展为整数,而不是字符串。
那么有没有一种方法可以在不调用将整数转换为 C 字符串的函数的情况下执行此操作?
您可以使用 #
运算符将宏参数字符串化。但是你需要一个间接的宏调用来扩展参数:
#define Q(x) Q_(x)
#define Q_(x) #x
所以你可以这样做:
char filebuffer[PATH_MAX + 10];
sprintf(filebuffer, "%." Q(PATH_MAX)"s.db", filename);
现有代码将字符串同级限制为 256 个字符,但随后添加了一个文件扩展名(和一个 NUL 终止符),当长度接近 256 时,这将是缓冲区溢出。我在上面使用了任意 10 字节的过度分配, 但最好使用像 snprintf
这样的检查长度的 sprintf。这将具有不需要宏游戏的额外优势。
正确的做法是在您的格式字符串中使用 *
,这将使它从您的参数列表中获取值。例如:
printf("%.*s\n", 3, "abcde");
这相当于:
printf("%.3s\n", "abcde");
这样您就可以使用 PATH_MAX
或任何其他值来控制格式,而不必担心它们是如何定义的(例如,它们是否包含括号或加法运算符等)
在为 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);
}
}
}
由于代码不是 windows 具体的,每个 256
值都应转换为 PATH_MAX
。
我知道在带引号的字符串中扩展宏是不可能的,但是字符串连接很简单:
#define STR "string"
size_t len=strlen("part"STR"part 2");
但是,诸如:
"%."PATH_MAX".db"
应该不起作用,因为PATH_MAX
扩展为整数,而不是字符串。
那么有没有一种方法可以在不调用将整数转换为 C 字符串的函数的情况下执行此操作?
您可以使用 #
运算符将宏参数字符串化。但是你需要一个间接的宏调用来扩展参数:
#define Q(x) Q_(x)
#define Q_(x) #x
所以你可以这样做:
char filebuffer[PATH_MAX + 10];
sprintf(filebuffer, "%." Q(PATH_MAX)"s.db", filename);
现有代码将字符串同级限制为 256 个字符,但随后添加了一个文件扩展名(和一个 NUL 终止符),当长度接近 256 时,这将是缓冲区溢出。我在上面使用了任意 10 字节的过度分配, 但最好使用像 snprintf
这样的检查长度的 sprintf。这将具有不需要宏游戏的额外优势。
正确的做法是在您的格式字符串中使用 *
,这将使它从您的参数列表中获取值。例如:
printf("%.*s\n", 3, "abcde");
这相当于:
printf("%.3s\n", "abcde");
这样您就可以使用 PATH_MAX
或任何其他值来控制格式,而不必担心它们是如何定义的(例如,它们是否包含括号或加法运算符等)