为什么printf("%d", ~0)输出-1?

4
为什么printf("%d", ~0); 的结果是 -1?按照逻辑不应该是1吗?因为 ~ 运算符会将每个1位变成0位,反之亦然。
据我所知,0000会被转换为1111

尝试运行 printf("%x", ~0);它将输出 ff。这意味着对每个位进行了取反操作,因此 0000000000000000 被转换为 1111111111111111。 根据逻辑,如果第一位是 1,则被视为负数。 因此结果为 -1。 - Nitin Tripathi
阅读关于整数如何以二进制补码的形式内部存储的文章。解释了为什么二进制全是1代表十进制的-1 - kaylum
C编译器在使用数字字面量时无法处理单个位。例如,在32位中,0是0。因此,~0将否定32位,而不仅仅是一个位。无论您写0、00还是000,它始终是具有32位的相同零。如果您写1,则为31个零和一个单独的1,否定它将再次否定所有32位。 - Sami Kuhmonen
@tuyen le:是的,0000 被转换成了 1111。但是你为什么期望二进制的 1111 位模式代表 1 呢??? - AnT stands with Russia
我之前没有意识到在二进制补码中,1111代表-1。因为0001的反码是1110。现在一切都清楚了。 - tuyen le
5个回答

2

~是按位取反运算符。将00000000翻转为11111111

如果你对1(00000001)2's补码,得到的是11111111,用于表示二进制中的-1

因此输出结果为-1


谢谢,现在一切都清楚了。 - tuyen le
@tuyenle 很好,干杯!! - ameyCU
这就是为什么在检查函数返回值状态(无论是正还是负)时使用 ~ 的原因。 - incompetent

2

尝试查看其十六进制部分。

printf("%x", ~0);

它将打印ffff,这意味着它否定了每个位,因此0000000000000000被转换为1111111111111111。 根据逻辑,如果第一位是1,则被视为负数。 因此-1


2
在C/C++中,~ 是按位补码运算符。对于任何可进行按位补码的对象 x,它将翻转在x的原始表示中找到的所有二进制位。因此,如果一个整数x以二进制形式表示为0b00000000,它将变为0x11111111
但是!!!
答案并不总是-1。存在两种表示负数的方式,即一补数和二补数。
一补数
对于任何数字x-x被表示为x的按位补码。
二补数
对于任何数字x-x被表示为加一x的按位补码。
现实世界
如果您能找到一个使用一补数的(现代)系统,我就送你一块免费的饼干!事实上,一补数允许一些无意义的情况发生,例如-0,事实上,在一补数机器上,您的代码将呈现这种情况。
顺便说一下,正如其他答案已经发布的那样,数字的实际打印(而不是内部表示)可能会因为它被转换而有所不同(无符号数只需忽略额外的最高位,因此在溢出之前可以允许两倍的范围)。

C标准还允许使用符号数和大小编码有符号数字。 - Bill Lynch
@BillLynch:如果你能找到一个使用/执行这个的(现代)系统,我会再给你一块免费的饼干! - 3442
由于没有合理的原因重复,评论已被删除。 - 3442

2

在32位机器上,0表示为

00000000000000000000000000000000

当您应用按位非(~)时,它会翻转所有位,然后位表示如下:
11111111111111111111111111111111 

这是2补码的-1表示法。

1
%d takes signed integer

different variations of same input

 Signed Value ~0 -1
UnSigned Value ~0 4294967295
Hex  Value ~0 ffffffff
Hex  Value ~0 FFFFFFFF

正如你所看到的,符号位被设置为1,实际上它就是-1的二进制补码

作为一个规则

-ve of n = (~n) + 1;
      complement of 5  is  -6 
 and  complement(5)+1  is   -5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接