【问题标题】:Why pass a compile-time-static string as a parameter to a string-formatting function instead of including it in the format string?为什么将编译时静态字符串作为参数传递给字符串格式化函数,而不是将其包含在格式字符串中?
【发布时间】:2019-12-01 01:45:29
【问题描述】:

在分析 Ghidra 的自动反编译器的 C 输出时,我发现了以下 sprintf 调用:

some_function(char *shm_name, int key, int subkey) {
    ...
    sprintf(shm_name,"%s%d_%d","/XSAL_Shm_",key,subkey);
    ...
}

如果我自己写这段代码,我会写

sprintf(shm_name,"/XSAL_Shm_%d_%d",key,subkey);

因为我认为它更清晰、更易于阅读和理解,而且 - 根据我的经验 - 更常见。

我正在分析的代码是为在 QNX 上运行而编写的。

有什么理由把它写成前者?是否有任何 C 风格指南要求/推荐任何一种方式?哪个更高效?

【问题讨论】:

  • readelf -wm executablefile 是否显示任何宏?也许原始代码有类似#define SHMPREFIX "/XSAL_Shm_"
  • @MarkPlotnick readelf -wm ... 不产生任何输出。不过,这是我没有考虑过的一个很好的理由。稍后在具有环境变量名称的同一函数中再次出现类似的东西,我绝对想象它会在宏中定义。这可能就是答案。
  • @MarkPlotnick 您应该将其发布为答案。

标签: c format-string


【解决方案1】:

这基本上是一个“风格”问题,这意味着任何答案(包括我的)都可能是固执己见的。这里没有“正确”或“错误”的答案。 (Stack Overflow 上通常不鼓励此类问题,按理说,我应该投票结束这个问题而不是回答它。但风格问题可能很有趣,所以就这样吧。)

如果常量字符串与变量字符串“非常相似”,或者我想象读者可能会想象常量部分可能会有所不同,或者如果我想象那个天常数部分实际上可能会有所不同。

但我不太喜欢您发布的代码的编写方式。如果我正在写它,并且如果我认为“常量”部分属于其余的论点,我会将它写成

sprintf(shm_name, "%s_%d_%d", "/XSAL_Shm", key, subkey);

或许

sprintf(shm_name, "/%s_%d_%d", "XSAL_Shm", key, subkey);

这两种形式中的任何一种都可以更容易地在一个地方看到标点符号的结构,在另一个地方看到三个不同的名称组成部分。

您谈到了“更清晰、更易于阅读和理解”的内容,显然这可能是一个意见和个人喜好问题。我同意将常量字符串与“变量”一起放入至少是令人惊讶的。然而,一旦读者克服了惊喜,我认为它可以更容易阅读和理解。 (但我当然不会断言每个读者都会发现它更容易理解,或者如果你仍然不同意你就错了。)

虽然我们正在讨论此代码,但我提出的另一个建议是将sprintf 替换为snprintf。假设shm_name 是一个固定大小的数组,我可能会使用

snprintf(shm_name, sizeof(shm_name) "/%s_%d_%d", "XSAL_Shm", key, subkey);

强调始终使用snprintf 是避免sprintf 出现缓冲区溢出可能性的简单方法。

(确实sprintf可以在某些情况下安全使用,事实上这是其中之一,因为在这种情况下%s、@987654331的扩展大小@ 和 %d 可以很容易地预测出来,因此您可以为 shm_name 提供一个不错的、真正安全的大小。但是由于 sprintf 的许多用途可能是不安全的——包括那些 %s 与更多任意字符串——养成始终使用snprintf 的习惯会更安全。)


附录:我错过了这个问题是关于反编译代码的事实。我同意其他几位评论员的观点,字符串"/XSAL_Shm_" 很可能是宏扩展的结果——换句话说,实际的原始代码可能类似于

#define XSAL_SHM_PREFIX "/XSAL_Shm_"

sprintf(shm_name, "%s%d_%d", XSAL_SHM_PREFIX, key, subkey);

这看起来并不奇怪。

【讨论】:

  • 这样做的一个客观原因可能是 "XSAL_Shm" 是宏扩展的结果,并且没有明确记录/强制宏必须在格式字符串中表现为文字上下文(即不包含%)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 2019-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多