昨天在调试中,遇到了一个奇怪的问题,伪码如下:
class SomeClass
{
public:
int SomeMethod();
private:
bool _someBool;
};
int SomeClass::SomeMethod()
{
int someInt;
//1
someInt = _someBool ? 5 : 2;
cout << "someInt=" << someInt << endl; //5
//2
someInt = (_someBool == true) ? 5 : 2;
cout << "someInt=" << someInt << endl; //2
return someInt;
}
int _tmain(int argc, _TCHAR* argv[])
{
SomeClass sc;
int r = sc.SomeMethod();
return 0;
}
原文中是写成 case 1 的形式。在debug build中,someInt=5,但是在release build中someInt=0。Windows上不是每次都复现,Linux上100%复现。在windows上直接debug SomeMethod,发现 VS intelligence 显示_someBool 为true。
在Registers窗口中看到:
EAX = CCCCCCCC EBX = 7EFDE000 ECX = 0025F867 EDX = 00000001 ESI = 00000000 EDI = 0025F780 EIP = 01131DB3 ESP = 0025F69C EBP = 0025F780 EFL = 00000212
Watch窗口:
看到2件事情:
1. _someBool 是bool型,显示为true,但是它的16进制表示却为0xcc (之前看到的是0xcd,都表示未初始化的内存)
----由于之前没有跟踪_someBool是如何来的(也没有看16进制值),直接在这个方法里面debug,被VS给误导了,为什么明明是true,却返回0给_someInt呢??!!原因是:定义了_someBool但没有初始化,所以值是undefined的,内存中的某个数据吧(我一直以为不赋值,默认就是false =_=)。VS 给啥说是true呢,因为VS 是把它跟0判断,如果不等于0,通通认为是true。
2. _someBool的内存地址是存储在 ECX 寄存器中。
断点到1处的语句时,go to disassembly。
someInt = _someBool ? 5 : 2;
010C1DB3 mov eax,dword ptr [this]
010C1DB6 movzx ecx,byte ptr [eax]
010C1DB9 neg ecx
010C1DBB sbb ecx,ecx
010C1DBD and ecx,3
010C1DC0 add ecx,2
010C1DC3 mov dword ptr [someInt],ecx
重点是neg, sbb两条语句。可认为ECX就是_someBool的值。
neg r : 语义是 0 - r -> r,减去任何非零数,都会产生借位,这句是在设置CF(Carry Flag)位。结合本例,ecx本来为1,执行完后,为-1,CF=1.
sbb r, r :语义是 r - r - CF -> r,设置 r 为0或者-1。结合本例,执行完后,ecx 为-1,即FFFFFFFF。所以如果最开始r是0,到这里也=0,如果不为0,到这里= -1。
之后的and, add是根据 ecx 的值,对 _someInt 赋值。
由此看出:这时 “?:” 这个三元赋值语句的条件判断,是在跟 0 比较。_someBool 值不为0,所以认为是true,返回5。
断点2处:
someInt = (_someBool == true) ? 5 : 2;
010C1E06 mov eax,dword ptr [this]
010C1E09 movzx ecx,byte ptr [eax]
010C1E0C sub ecx,1
010C1E0F neg ecx
010C1E11 sbb ecx,ecx
010C1E13 and ecx,0FFFFFFFDh
010C1E16 add ecx,5
010C1E19 mov dword ptr [someInt],ecx
sub r, 1 :先将ecx值 -1,再做neg和sbb的运算。这时是在跟 1 比较。也就是说,true的值 = 1。_someBool的值不为1,所以为false,返回2。
总结:
1. 成员定义先赋初始默认值。
2. VS 判断bool,是跟0比较,不=0,为true。
3. 布尔型 true 的值为1,“? :” 三元运算符的2种处理。