Debug "somebool == true" 的陷阱

    昨天在调试中,遇到了一个奇怪的问题,伪码如下:

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种处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值