在引用的字符串

时间:2016-05-30 22:07:35

标签: 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)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字符串的函数的情况下执行此操作?

2 个答案:

答案 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会更好。这将具有不需要宏观游戏的额外优势。