在使用TM4C123GXL时,我遇到了一个奇怪的行为,我认为这是编译器造成的。(TI v220.2.5.LTS(当将逐位否定函数与等价运算符结合使用时,编译器似乎没有正确遵循操作顺序。
从本质上讲,你会发现选项#1不会起作用,并且会导致错误,即使它应该是正确的(从我所看到的(。然而,选项#2将起作用,并将产生正确的结果。(在我看来,这与不必要的变量声明是一样的(
选项#1(应该有效,但不行(
uint8_t foo = 0x40; // 0100 0000
uint8_t fooinv = 0xBF; // 1011 1111
uint8_t bar = 0x04; // 0000 0100
uint8_t barinv = 0xFB; // 1101 1111
bool valid = true;
valid = (foo == ~fooinv) && valid;
valid = (bar == ~barinv) && valid;
选项#2(额外变量但有效(
uint8_t foo = 0x40; // 0100 0000
uint8_t fooinv = 0xBF; // 1011 1111
uint8_t bar = 0x04; // 0000 0100
uint8_t barinv = 0xFB; // 1101 1111
uint8_t temp1 = ~fooinv;
uint8_t temp2 = ~barinv;
bool valid = true;
valid = (foo == temp1) && valid;
valid = (bar == temp2) && valid;
我怀疑这是因为可能存在某种未解决的数据隐患,但我无法确定这里发生了什么。我还没有对编译器创建的代码进行反汇编,但任何帮助都将不胜感激。
~
的行为在C 2018 6.5.3.3 4中指定,包括:
…对操作数执行整数提升,结果具有提升类型…
整数提升将uint8_t
转换为int
。因此,在~fooinv
中,fooinv
的值0xBF
被转换为int
。这不会改变数值;它仍然是0x000000BF
,这是相同的值,只是显示了更多的比特。(对于这个答案,我将使用32位的int
,这在C实现中很常见。(然后执行逐位求反得到0xFFFFFF40
。这与foo
、0x40
的值不同,因此foo == ~fooinv
当然会产生假(零(。
如果你想计算fooinv
的逐位否定在uint8_t
中是什么,你可以简单地转换结果:(uint8_t) ~fooinv
。比较CCD_ 17得出真(一(。
问题是在这些表达式中
valid = (foo == ~fooinv) && valid;
valid = (bar == ~barinv) && valid;
使用将类似于此CCD_ 18的操作数转换为类型CCD_。实际上,您正在处理的是值=0xFFFFFF40
。
来自C标准(6.5.3.3一元算术运算符(
4 ~运算符的结果是其(提升(操作数(即,结果中的每个位都设置为当且仅如果未设置转换后的操作数中的对应位(对操作数执行整数提升,结果为提升的类型。如果提升的类型是无符号类型,则表达式~E等价于其中可表示的最大值类型减去E.
因此,要获得预期结果,您应该编写
valid = (foo == ( uint8_t )~fooinv) && valid;
valid = (bar == ( uint8_t )~barinv) && valid;