在 C 中,为什么 %o 不能打印负值?
In C, why can't %o print negative values?
所以当我 运行 这个:
printf("%o", -1);
打印出37777777777
.
为什么我会得到这个输出?
我以为是-1
的第一个补码,可是为什么3
在开头呢?
根据 ISO C 标准 (C11 7.21.6.1 The fprintf function /8
),%o
打印出一个 unsigned 八进制值:
o,u,x,X - The unsigned int
argument is converted to unsigned octal (o
), unsigned decimal (u
), or unsigned hexadecimal notation (x
or X
) ...
根据您的输出,您有一个 32 位二进制补码 int
类型,其中 -1
表示为二进制:
11111111 11111111 11111111 11111111
\/\_/\_/ \_/\_/\__/\_/\_/\__/\_/\_/
3 7 7 7 7 7 7 7 7 7 7
底线显示八进制表示(您所看到的)。
原因为什么你在前面看到 3
是因为每个八进制数字代表三位,而 32 不能被三整除。
但是,您应该记住,任何 行为在这里都是可以接受的。根据上面的 ISO 引用,%o
需要一个 unsigned int
,并且根据后面的小节 /9
:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
如果您的 int
是 64 位的,它会略有不同(当然也更长)。一个 32 位值将在前面有两个额外的位 (32 % 3 == 2
),而一个 64 位值只有一个 (64 % 3 == 1
)。所以你最终会得到:
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
|\_/\_/\__/\_/\_/ \_/\_/\__/\_/\_/\__/\_/\_/ \_/\_/\__/\_/\_/\__/\_/\_/
1 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
虽然以十进制以外的任何基数显示带符号数通常没有多大意义,但十进制没有什么特别之处,表明它是唯一可以显示负数的基数。
例如,如果您有两个地址,您可能想知道它们之间的区别,可能是负数。当然,您希望看到该结果为十六进制。
事实上,Python 完全可以原生显示负十六进制值。
因此,这里有一种使用 %d
以外的说明符显示负数的方法,即 %o
:
int x = -1;
printf("%s%o", x<0 ? "-" : "", x<0 ? 0u-x : 0u+x);
没有直接的方法可以打印八进制甚至十六进制的负数!!幸运的是,很少需要这样做。你当然可以测试数字是否为负数并在它前面打印一个负号:
if (i < 0)
printf("-%o",-i);
else
printf("%o",i);
所以当我 运行 这个:
printf("%o", -1);
打印出37777777777
.
为什么我会得到这个输出?
我以为是-1
的第一个补码,可是为什么3
在开头呢?
根据 ISO C 标准 (C11 7.21.6.1 The fprintf function /8
),%o
打印出一个 unsigned 八进制值:
o,u,x,X - The
unsigned int
argument is converted to unsigned octal (o
), unsigned decimal (u
), or unsigned hexadecimal notation (x
orX
) ...
根据您的输出,您有一个 32 位二进制补码 int
类型,其中 -1
表示为二进制:
11111111 11111111 11111111 11111111
\/\_/\_/ \_/\_/\__/\_/\_/\__/\_/\_/
3 7 7 7 7 7 7 7 7 7 7
底线显示八进制表示(您所看到的)。
原因为什么你在前面看到 3
是因为每个八进制数字代表三位,而 32 不能被三整除。
但是,您应该记住,任何 行为在这里都是可以接受的。根据上面的 ISO 引用,%o
需要一个 unsigned int
,并且根据后面的小节 /9
:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
如果您的 int
是 64 位的,它会略有不同(当然也更长)。一个 32 位值将在前面有两个额外的位 (32 % 3 == 2
),而一个 64 位值只有一个 (64 % 3 == 1
)。所以你最终会得到:
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
|\_/\_/\__/\_/\_/ \_/\_/\__/\_/\_/\__/\_/\_/ \_/\_/\__/\_/\_/\__/\_/\_/
1 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
虽然以十进制以外的任何基数显示带符号数通常没有多大意义,但十进制没有什么特别之处,表明它是唯一可以显示负数的基数。
例如,如果您有两个地址,您可能想知道它们之间的区别,可能是负数。当然,您希望看到该结果为十六进制。
事实上,Python 完全可以原生显示负十六进制值。
因此,这里有一种使用 %d
以外的说明符显示负数的方法,即 %o
:
int x = -1;
printf("%s%o", x<0 ? "-" : "", x<0 ? 0u-x : 0u+x);
没有直接的方法可以打印八进制甚至十六进制的负数!!幸运的是,很少需要这样做。你当然可以测试数字是否为负数并在它前面打印一个负号:
if (i < 0)
printf("-%o",-i);
else
printf("%o",i);