在Linux上,我正在使用GNU gcc 4.9.2版本,并在尝试打印指定长度的零填充字符串时出现奇怪的意外行为。这是我正在尝试的代码片段:
#include <cstdio>
#include <cstring>
int main()
{
char buff[5];
sprintf(buff,"%04s","12");
printf("%s\n", buff);
return 0;
}
虽然http://www.cplusplus.com/reference/cstdio/printf/中给出的文档明确指出,当指定填充时,标志左边用数字填充零(0)而不是空格。 但是,它的打印空间填充“12”,即“12”而不是“0012”。 补救?
答案 0 :(得分:5)
在manpage of printf中,您会找到一个确切的解释:
0
该值应为零填充。对于
d
,i
,o
,u
,x
,X
,a
,A
,{ {1}},e
,E
,f
,F
和g
次转换,转换后的值用零填充而不是空格。 [...]对于其他转换,行为未定义。
因此,它没有为字符串定义。实现可以填充0但不必。这是未定义的行为。
以下解决方案使用G
语法作为格式说明符,因此不需要使用for循环或多个printf调用。
%.*s
此外,您应该考虑使用char buff[5];
char str[] = "12";
size_t len = strlen(str);
sprintf(buff, "%.*s%s", len >= 4 ? 0 : (int)(4 - len), "0000", str);
来防止缓冲区溢出。
snprintf
带有snprintf(buff, sizeof(buff), "%.*s%s", len >= 4 ? 0 : (int)(4 - len), "0000", str);
的格式化输出可能会因不同的编译器而异。在Linux gcc下,它总是附加一个尾随空字节snprintf
。如果要写入的字符串大于或等于缓冲区,Visual Studio 2010编译器不会确保。
答案 1 :(得分:3)
C11 7.21.6.1p6明确指出tlbimp
与0
转换说明符一起的行为未定义:
<强>
s
强>对于
0
,d
,i
,o
,u
,x
,X
,{{1} },a
,A
,e
,E
,f
和F
次转化,前导零(跟随符号或基数的任何指示)用于填充字段宽度而不是执行空间填充,除非转换无穷大或NaN。如果同时显示g
和G
标记,则忽略0
标记。对于-
,0
,d
,i
,o
,u
次转化,如果指定了精度,x
标志被忽略。 对于其他转化,行为未定义。
因此X
的行为未定义,而且当它与您的期望不相符时,您就会幸运!
所以,这里a complete library最有效地进行左键操作:
0
这也适用于任何填充字符和任何填充长度。用法示例:
%04s
当然,如果字符串恰好是负十进制字符串(填充将在 - 符号之前),这不起作用。