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);
这是完全合法的代码,但是
- 如果您只想复制字符串,请改用
strcpy()
。
- 如果您正在处理用户输入,您可能会使自己容易受到 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);
~~~~~~~ ^
我已经阅读了 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);
这是完全合法的代码,但是
- 如果您只想复制字符串,请改用
strcpy()
。 - 如果您正在处理用户输入,您可能会使自己容易受到 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);
~~~~~~~ ^