刚刚遇到一些(非常)遗留代码(最初编写为C但现在编译为C ++)并使用宽度说明符来填充字符串
void main()
{
unsigned long val = 2413;
printf("V1: %08lu \n", val);
printf("V2: %8.8lu \n", val);
}
结果相同
V1: 00002413
V2: 00002413
那么为什么会使用V2呢?从昔日开始,它是std lib的遗留方面吗?
编译器详细信息:用于x86的Microsoft(R)C / C ++优化编译器版本19.10.25019
答案 0 :(得分:16)
对于无符号整数类型,没有区别。对于 signed 整数类型的负值,您将看到不同的输出
long val = -2413;
printf("V1: %08ld\n", val);
printf("V2: %8.8ld\n", val);
V1: -0002413
V2: -00002413
.8
的{{1}}部分指定要显示的最小位数。并且%8.8ld
符号不被视为数字。因此,第二个版本需要始终打印8位数。如果值为负,则-
符号将无法选择,而是成为第9个字符,因此违反了请求的字段宽度8。
-
版本无需打印至少8位数,这就是为什么%08ld
符号占据里面的字段宽度为8且只有7位数的原因印刷。
答案 1 :(得分:7)
正如我在评论中提到的,使用字符串时,%8s
和%8.8s
之间存在差异 - 如果字符串长于8
,后者会截断。还有另一个不同之处; 0
不是%s
的有效修饰符。 %8.8lu
与%.8lu
没有什么不同; %.8lu
和%08lu
之间没有太大区别,但0
较旧且.
已添加到C90(这些日子已经很久了)。但是,当值为负数时,%.8ld
和%08ld
之间存在差异。
以下是一些代码,用于说明printf()
的整数格式的一些变幻莫测 - 对于有符号和无符号值。请注意,如果您有%8.6lu
而非%8.8lu
(类似于已签名),则会产生有趣的差异。
#include <stdio.h>
static void test_ul(void)
{
char *fmt[] =
{
"%08lu",
"%8.8lu",
"%.8lu",
"%8.6lu",
"%6.8lu",
};
enum { NUM_FMT = sizeof(fmt) / sizeof(fmt[0]) };
unsigned long val[] = { 2413LU, 234512349LU };
enum { NUM_VAL = sizeof(val) / sizeof(val[0]) };
for (int i = 0; i < NUM_FMT; i++)
{
for (int j = 0; j < NUM_VAL; j++)
{
printf("%8s: [", fmt[i]);
printf(fmt[i], val[j]);
puts("]");
}
}
}
static void test_sl(void)
{
char *fmt[] =
{
"%08ld",
"%8.8ld",
"%.8ld",
"%8.6ld",
"%6.8ld",
};
enum { NUM_FMT = sizeof(fmt) / sizeof(fmt[0]) };
long val[] = { +2413L, -2413L, +234512349L, -234512349L };
enum { NUM_VAL = sizeof(val) / sizeof(val[0]) };
for (int i = 0; i < NUM_FMT; i++)
{
for (int j = 0; j < NUM_VAL; j++)
{
printf("%8s: [", fmt[i]);
printf(fmt[i], val[j]);
puts("]");
}
}
}
int main(void)
{
test_ul();
test_sl();
return 0;
}
输出(macOS Sierra 10.12.5上的GCC 7.1.0):
%08lu: [00002413]
%08lu: [234512349]
%8.8lu: [00002413]
%8.8lu: [234512349]
%.8lu: [00002413]
%.8lu: [234512349]
%8.6lu: [ 002413]
%8.6lu: [234512349]
%6.8lu: [00002413]
%6.8lu: [234512349]
%08ld: [00002413]
%08ld: [-0002413]
%08ld: [234512349]
%08ld: [-234512349]
%8.8ld: [00002413]
%8.8ld: [-00002413]
%8.8ld: [234512349]
%8.8ld: [-234512349]
%.8ld: [00002413]
%.8ld: [-00002413]
%.8ld: [234512349]
%.8ld: [-234512349]
%8.6ld: [ 002413]
%8.6ld: [ -002413]
%8.6ld: [234512349]
%8.6ld: [-234512349]
%6.8ld: [00002413]
%6.8ld: [-00002413]
%6.8ld: [234512349]
%6.8ld: [-234512349]
答案 2 :(得分:5)
当您在ref中阅读时,这两个与unsigned long
(/整数)一起使用时是等效的。
printf("V1: %08lu \n", val);
当指定填充时, 0
标志将使用零(0)而不是空格填充数字(请参阅width子说明符)。
8
将是number
,在“要打印的最小字符数中。如果要打印的值小于此数字,则结果将填充空格。值为即使结果较大,也不会被截断。“
现在这个:
printf("V2: %8.8lu \n", val);
会将8
的效果保持为number
,但会将.8
添加为“{1}}”,对于“整数说明符”(d,i,o,u,x ,X):precision指定要写入的最小位数。如果要写入的值小于此数字,则结果用前导零填充。即使结果较长,该值也不会被截断。 0表示没有为值0写入字符。“。
PS:标准C ++应该发出诊断错误:
.number
然而,即使Stroustrup他自己说这“不是也不是C ++,甚至也不是C”。
答案 3 :(得分:0)
实际上,%8.8
和{{1}}之间没有任何区别,除非你进入十进制数字,然后就会有所不同。这一切都取决于用户喜欢它的方式。这只是一种偏好。