C中有符号和无符号整数的按位NOT

时间:2017-03-28 23:47:37

标签: c gcc signed

我正在调试一个问题,并发现以下代码段(已消毒)就是问题的原因。

uint64_t testflag = 0;
testflag &= ~(0x08ul); //bug 
testflag &= ~(0x08l);  //expected 

我比较了生成的程序集并看到了这个

  uint64_t testflag = 0;
804851e:    c7 45 d8 00 00 00 00    movl   $0x0,-0x28(%ebp)
8048525:    c7 45 dc 00 00 00 00    movl   $0x0,-0x24(%ebp)
  testflag &= ~(0x08ul);
804852c:    83 65 d8 f7             andl   $0xfffffff7,-0x28(%ebp)
8048530:    83 65 dc 00             andl   $0x0,-0x24(%ebp)
  testflag &= ~(0x08l);
8048534:    83 65 d8 f7             andl   $0xfffffff7,-0x28(%ebp)
8048538:    83 65 dc ff             andl   $0xffffffff,-0x24(%ebp)

为什么NOT operator的{​​{1}}会导致编译器使用较高字节而不是unsigned long0进行对比。

我的gcc版本在64位计算机上为ffffffff

1 个答案:

答案 0 :(得分:1)

假设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的符号位被扩展。 @Marc Glisse