在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”。补救办法?
发布于 2017-07-20 12:56:30
C11 7.21.6.1p6明确指出,0与s转换说明符结合在一起的行为没有定义:
0对于d、i、o、u、x、X、a、A、e、E、f、F、g和G转换,前导零(跟随符号或基的任何指示)用于填充字段宽度,而不是执行空格填充,除非转换无穷大或NaN。如果0和-标志同时出现,则忽略0标志。对于d、i、o、u、x、X转换,如果指定了精度,则忽略0标志。对于其他转换,行为是未定义的.
因此,%04s的行为是没有定义的,当它不符合您的期望时,您是幸运的!
因此,下面是用于最有效地执行左侧衬垫操作的一个完整的图书馆:
char *leftpad(char *str, size_t length, char fill, char buf[]) {
size_t s_len = strlen(str);
if (s_len > length) {
return NULL;
}
size_t padding = length - s_len;
memset(buf, fill, padding);
strcpy(buf + padding, str);
return buf;
}这也可以很好地处理任何填充字符和填充长度。用法示例:
int main(void) {
char buf[65], *s;
if (s = leftpad(buf, 64, '0', "12")) {
puts(s);
}
}当然,如果字符串恰好是负数十进制字符串(填充将位于-符号之前),这就不起作用了。
发布于 2017-07-20 12:47:59
在印刷手册中,您会发现一个确切的指示:
0值应该是零填充。对于d、i、o、u、x、X、a、A、e、E、f、F、g和G转换,转换后的值将用零而不是空格填充在左边。..。对于其他转换,行为是未定义的。
因此,它不是为字符串定义的。实现可以使用0进行填充,但不必使用0。这是不确定的行为。
以下解决方案使用%.*s语法作为格式说明符,因此不需要使用for循环或多个printf调用。
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);带有snprintf的格式化输出在不同编译器中的行为可能有所不同。在Linux下,它总是附加一个拖尾的空字节'\0'。Visual 2010编译器不能确保如果要写入的字符串更大或等于缓冲区。
https://stackoverflow.com/questions/45214773
复制相似问题