Linux:打印指定长度的零填充字符串

时间:2017-07-20 12:30:21

标签: c format-specifiers

在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”。 补救?

2 个答案:

答案 0 :(得分:5)

manpage of printf中,您会找到一个确切的解释:

  

0

     

该值应为零填充。对于diouxXaA,{ {1}},eEfFg次转换,转换后的值用零填充而不是空格。 [...]对于其他转换,行为未定义。

因此,它没有为字符串定义。实现可以填充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明确指出tlbimp0转换说明符一起的行为未定义:

  

<强> s

     

对于0diouxX,{{1} },aAeEfF次转化,前导零(跟随符号或基数的任何指示)用于填充字段宽度而不是执行空间填充,除非转换无穷大或NaN。如果同时显示gG标记,则忽略0标记。对于-0diou次转化,如果指定了精度,x标志被忽略。 对于其他转化,行为未定义。

因此X的行为未定义,而且当它与您的期望不相符时,您就会幸运

所以,这里a complete library最有效地进行左键操作:

0

这也适用于任何填充字符和任何填充长度。用法示例:

%04s

当然,如果字符串恰好是十进制字符串(填充将在 - 符号之前),这不起作用。