如何解释sprintf的这种行为?

时间:2015-07-06 13:45:43

标签: c string printf

所以情况很简单:我需要在c字符串前添加一个字符。

所以我有了我的代码:

char *a = "2233b";
char output[100];   
char toAdd = '-';

strcpy(output, a);
printf("\noutput=%s", output);
sprintf(output, "%c%s",  toAdd, a);
printf("\noutput=%s", output);

输出结果符合预期:

  

output=2233b
  output=-2233b

好的,到目前为止一切顺利。现在情况发生了变化,我想在c字符串之前添加更多字符,所以我配置了代码:

char *a = "2233b";
char output[100];   
char toAdd = '-';

strcpy(output, a);
printf("\noutput=%s", output);
sprintf(output, "%c%s",  toAdd, a);
printf("\noutput=%s", output);
sprintf(output, "%c%s",  toAdd, output);
printf("\noutput=%s", output);

我希望输出为:

  

output=2233b
  output=-2233b
  output=--2233b

但事实并非如此,我的屏幕上印有以下输出:

  

output=2233b
  output=-2233b
  output=-------

Check working example here

为什么output包含此值? 因为格式只是字符(%ctoAdd'-')和字符串(%s),output并且包含("-2233b" })。

那么为什么最后一个输出不包含"--2233b"?为什么output的字符都转换为'-'

3 个答案:

答案 0 :(得分:3)

我认为问题出在

 sprintf(output, "%c%s",  toAdd, output);

在这里,您在一个有序的语句中读取和写入output。这会调用undefined behaviour

引用C11,章节§7.21.6.6,sprintf()函数

  

如果在重叠的对象之间进行复制,则行为未定义。

答案 1 :(得分:1)

这是调用未定义的行为,如* nix系统上的相应man页面以及CPOSIX标准中所述。

NOTES
   Some programs imprudently rely on code such as the following

       sprintf(buf, "%s some further text", buf);

   to append text to buf.  However, the standards explicitly  note  that  the
   results are undefined if source and destination buffers overlap when call‐
   ing sprintf(), snprintf(), vsprintf(), and vsnprintf().  Depending on  the
   version  of  gcc(1) used, and the compiler options employed, calls such as
   the above will not produce the expected results.

   The glibc implementation of the functions snprintf() and vsnprintf()  con‐
   forms  to  the  C99  standard,  that is, behaves as described above, since
   glibc version 2.1.  Until glibc 2.0.6, they would return -1 when the  out‐
   put was truncated.

答案 2 :(得分:1)

标准禁止传递对输入和输出重叠的缓冲区,因此行为未定义。

如果您有兴趣了解为什么会出现多个短划线,那么接下来会发生什么:问题是当您将output作为输入传递给sprintf时,这个函数的行为就像一条狗追逐自己的尾巴:它在读取它的第一个字符之前将第一个字符写入output ,然后在它尝试时将其写入“正面运行”其读取,但未成功处理%s格式:新函数会在函数读取时添加到输出中。

要解决此问题,请在将output传递给sprintf之前制作一份var table = $('#example').dataTable( { ..... table.fnUpdate(['x','y','z','4','X'], 0); 的临时副本。