sprintf() 是否需要格式说明符才能正常工作?

Does sprintf() require format specifiers to work properly?

我已经阅读了 post sprintf format specifier replace by nothing 和其他相关内容,但还没有看到具体说明。

直到今天,我从未见过 sprintf 仅使用 2 个参数。
我的系统用于 sprintf() 的原型是:

int sprintf (char Target_String[], const char Format_String[], ...);

在处理一些遗留代码时,我 运行 跨越了这个:(为了说明而简化)

char toStr[30];
char fromStr[]={"this is the in string"};
sprintf(toStr, fromStr);

我对原型的解释是,第二个参数应该由 const char[] 组成,并接受标准的 ansi C 格式说明符 such as these

但是上面的示例似乎可以很好地使用字符串 fromStr 作为第二个参数。
这纯粹是通过未定义的行为起作用的吗?还是这种用法完全合法?

我正在研究 Windows 7,使用 C99 编译器。

您观察到的行为是正确的,格式字符串不需要有任何转换说明符。在这种情况下,由 ... 表示的可变长度参数列表的长度为零。这是完全合法的,尽管它的效率肯定低于它的等价物

strcpy(toStr, fromStr);

这是完全合法的代码,但是

  1. 如果您只想复制字符串,请改用 strcpy()
  2. 如果您正在处理用户输入,您可能会使自己容易受到 format string attack

sprintf 的概要是:

int sprintf(char *str, const char *format, ...);

这意味着 2 个参数是合法的选项。

之所以有效,是因为您没有其他参数(即没有控制格式 %)要打印。

和没有第二个参数的printf没有区别:

int printf ( const char * format, ... );

如果你没有任何第二个参数,它也可以工作:

printf(fromStr);

完全合法。可变参数是可选的。

在这种情况下,printf 用作 strcpy,但解析 % 说明符的 fmt 字符串。

我会写 sprintf(toStr,"%s",fromStr); 这样它就不必解析那么长的字符串。

the second argument should be comprised of a const char[]

函数参数的 const 说明符保证函数不会更改该参数的值(假设它可以更改它,数组就是这种情况,因为它们是通过地址传递给函数的) .它不需要在实际调用中使用 const 值。

您发布的代码没有使用 const 字符串作为 sprintf() 的第二个参数,但是从非常量到 const 的转换是隐式的;那里不用担心。

accepting standard ansi C format specifiers

"accepting" 并不代表 "requiring"。您指定的格式字符串不包含任何格式说明符。因此,该函数仅使用 2 个参数调用(没有要格式化的值)。 sprinf() 无论如何都会忽略第三个参数,许多现代编译器会发出警告。


更新:我不想开始争论哪些编译器是现代的,哪些不是。

碰巧我在 OSX 10.11 上使用默认编译器,这是它输出的内容:

axiac: ~/test$ cc -v
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.3.0
Thread model: posix
axiac: ~/test$ cc -o 1 1.c
1.c:8:25: warning: data argument not used by format string [-Wformat-extra-args]
    sprintf(x, "abc\n", n);
               ~~~~~~~  ^