【问题标题】:Trailing zero as a result of snprintf由于 snprintf 导致尾随零
【发布时间】:2015-05-29 10:14:00
【问题描述】:

今天我遇到了一个我无法解决的问题。考虑这段代码 sn-p:

static const char *LOG_MESSAGES[] = {"String1.", "A longer string 2.", "String 3"};

main() 函数的某个地方,我写道:

printf("%s\n", LOG_MESSAGES[1]);//Prints "A longer string 2." as expected.
char rawLog[100] = {0};
printf("%s\n", rawLog);//Prints an empty string as expected.
snprintf(rawLog, 100, LOG_MESSAGES[1]);
printf("%s\n", rawLog);//Prints "A longer string 2.0". Adds a zero at the end.

我可能遗漏了一些明显的东西,但是这个尾随的零对我来说毫无意义。如果我改变了

snprintf(rawLog, 100, LOG_MESSAGES[1]);

snprintf(rawLog, strlen(LOG_MESSAGES[1]), LOG_MESSAGES[1]);

零消失。尽管如此,即使给定的大小为 100,snprintf() 也应该在 LOG_MESSAGES[1] 的末尾停止。

这个零是从哪里来的?

【问题讨论】:

  • 最后'.'重写为'\0'
  • 投票结束:问题中的代码不会导致问题(在 cmets 中发现该错误实际上是在不同的代码中)。

标签: c string printf


【解决方案1】:

编辑:

根据cmets收到的信息,案例1是本案例的问题。


在你的情况下,两个

 snprintf(rawLog, 100, LOG_MESSAGES[1]);                    //..........case 1

snprintf(rawLog, strlen(LOG_MESSAGES[1]), LOG_MESSAGES[1]); //..........case 2

是错误的,考虑到LOG_MESSAGES[1] 字符串可能本身包含某种形式的格式说明符。

  • 案例 1:您忘记了格式字符串,例如 %s
  • 案例 2: 案例 1,另外,您没有编写整个字符串。请记住,strlen()计算 size 中的终止空字节。您至少需要strlen(LOG_MESSAGES[1]) + 1 来编写整个 字符串内容以及空终止符。

【讨论】:

  • @Eregrith 抱歉误导您,实际的字符串实际上包含格式说明符。只是为了这个问题,我用更用户友好的英文字符串替换了它。
  • @SouravGhosh OP 的评论澄清了这一点。我同意您应该从不使用任何变量字符串(尤其是用户输入)代替格式字符串。
  • 7.19.6.5 snprintf 函数 2 第 n-1 个输出字符被丢弃而不是写入数组,并在实际写入数组的字符的末尾。
  • snprintf 危险。它总是附加一个尾随空值。 (除非您实际上将 0 作为缓冲区大小传递)
  • @BLUEPIXY 我太傻了。我把snprintf() 误认为strncpy()。我的错。 :(
【解决方案2】:

改正

snprintf(rawLog, 100, "%s\n", LOG_MESSAGES[1]);

在您的示例中,您使用 LOG_MESSAGES[1] 作为格式,而不是作为要复制到 rawlog 的文本。

【讨论】:

  • 是的,但为什么"A longer string 2." 会产生这样的错误?它不包含任何 '%' 并且以空值结尾。它按原样编写,无需使用任何其他参数。
  • 当我看到现在已删除的答案时,我意识到 snprintf 没有格式说明符会复制整个缓冲区。
猜你喜欢
  • 1970-01-01
  • 2020-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-29
  • 1970-01-01
  • 2022-10-14
  • 2011-05-30
相关资源
最近更新 更多