C中有符号和无符号整数的按位非
bitwise NOT of signed and unsigned integers in C
我正在调试一个问题,发现以下代码段(已清理)是问题的原因。
uint64_t testflag = 0;
testflag &= ~(0x08ul); //bug
testflag &= ~(0x08l); //expected
我比较了生成的程序集并看到了这个
uint64_t testflag = 0;
804851e: c7 45 d8 00 00 00 00 movl [=11=]x0,-0x28(%ebp)
8048525: c7 45 dc 00 00 00 00 movl [=11=]x0,-0x24(%ebp)
testflag &= ~(0x08ul);
804852c: 83 65 d8 f7 andl [=11=]xfffffff7,-0x28(%ebp)
8048530: 83 65 dc 00 andl [=11=]x0,-0x24(%ebp)
testflag &= ~(0x08l);
8048534: 83 65 d8 f7 andl [=11=]xfffffff7,-0x28(%ebp)
8048538: 83 65 dc ff andl [=11=]xffffffff,-0x24(%ebp)
为什么 unsigned long
的 NOT operator
会导致编译器将 0
与更高的字节而不是 ffffffff
.
我的 gcc 版本在 64 位机器上是 gcc (GCC) 4.9.2 (Red Hat 4.9.2)
。
假设 32 位 unsigned long/long
...
uint64_t testflag;
0x08ul --> 00 00 00 08
~(0x08ul) --> FF FF FF F7
some_uint32_t = FF FF FF F7
testflag &= some_uint32_t;
testflag = testflag & some_uint32_t
testflag = testflag & (uint64_t) some_uint32_t
testflag = testflag & (uint64_t) FF FF FF F7 (or 4,294,967,288)
testflag = testflag & 00 00 00 00 FF FF FF F7
将 32 位无符号数转换为 uint64_t
是一个简单的 0 扩展。
现在 ~(0x08l)
0x08l --> 00 00 00 08
~(0x08l) --> FF FF FF F7
some_int32_t = FF FF FF F7
testflag &= some_int32_t;
testflag = testflag & some_int32_t
testflag = testflag & (uint64_t) some_int32_t
testflag = testflag & (uint64_t) FF FF FF F7 (or - 8)
testflag = testflag & FF FF FF FF FF FF FF F7 (or 18,446,744,073,709,551,608)
-8 作为 uint64_t
非常接近 uint64_t
的最大值。
使用 2 的补码,结果是扩展了 OP 的 long
的符号位。
我正在调试一个问题,发现以下代码段(已清理)是问题的原因。
uint64_t testflag = 0;
testflag &= ~(0x08ul); //bug
testflag &= ~(0x08l); //expected
我比较了生成的程序集并看到了这个
uint64_t testflag = 0;
804851e: c7 45 d8 00 00 00 00 movl [=11=]x0,-0x28(%ebp)
8048525: c7 45 dc 00 00 00 00 movl [=11=]x0,-0x24(%ebp)
testflag &= ~(0x08ul);
804852c: 83 65 d8 f7 andl [=11=]xfffffff7,-0x28(%ebp)
8048530: 83 65 dc 00 andl [=11=]x0,-0x24(%ebp)
testflag &= ~(0x08l);
8048534: 83 65 d8 f7 andl [=11=]xfffffff7,-0x28(%ebp)
8048538: 83 65 dc ff andl [=11=]xffffffff,-0x24(%ebp)
为什么 unsigned long
的 NOT operator
会导致编译器将 0
与更高的字节而不是 ffffffff
.
我的 gcc 版本在 64 位机器上是 gcc (GCC) 4.9.2 (Red Hat 4.9.2)
。
假设 32 位 unsigned long/long
...
uint64_t testflag;
0x08ul --> 00 00 00 08
~(0x08ul) --> FF FF FF F7
some_uint32_t = FF FF FF F7
testflag &= some_uint32_t;
testflag = testflag & some_uint32_t
testflag = testflag & (uint64_t) some_uint32_t
testflag = testflag & (uint64_t) FF FF FF F7 (or 4,294,967,288)
testflag = testflag & 00 00 00 00 FF FF FF F7
将 32 位无符号数转换为 uint64_t
是一个简单的 0 扩展。
现在 ~(0x08l)
0x08l --> 00 00 00 08
~(0x08l) --> FF FF FF F7
some_int32_t = FF FF FF F7
testflag &= some_int32_t;
testflag = testflag & some_int32_t
testflag = testflag & (uint64_t) some_int32_t
testflag = testflag & (uint64_t) FF FF FF F7 (or - 8)
testflag = testflag & FF FF FF FF FF FF FF F7 (or 18,446,744,073,709,551,608)
-8 作为 uint64_t
非常接近 uint64_t
的最大值。
使用 2 的补码,结果是扩展了 OP 的 long
的符号位。