在 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);