代码中的隐式转换问题

今天在调试代码的时候,碰到一个很奇怪的现象,一条简单的语句,执行结果就是不对。

代码如下

int pack_size = recbuffer[1] + (rec_buffer_[0] << 8)

其中recbuffer为char类型,recbuffer[1]的值是0xd6,recbuffer[0]的值是0x01,预期的结果pack_size应为0x01d6。

根据c++的算术运算隐式转换规则,recbuffer[1]和recbuffer[0]都会被提升为整型,pack_size = 0xd6 + 0x100, 而实际执行结果确是0xd6。令我百思不得其解。

实在是没办法,将代码拆分为如下:

int pack_size = rec_buffer_[0];

pack_size <<= 8;

pack_size += rec_buffer_[1];

结果依然一样,还是0xd6,单步跟踪后,发现在pack_size+=recbuffer[1]这里,pack_size += rec_buffer_[1]执行后,pack_size从0x100变为0xd6,高位居然丢失了!

没办法,转到汇编,得到如下代码:

int pack_size = rec_buffer_[0];
01422A2A  mov         eax,dword ptr [ebp-14h]  
01422A2D  movsx       ecx,byte ptr [eax+71h]  
01422A31  mov         dword ptr [pack_size],ecx  
pack_size <<= 8;
01422A34  mov         eax,dword ptr [pack_size]  
01422A37  shl         eax,8  
01422A3A  mov         dword ptr [pack_size],eax  
pack_size += rec_buffer_[1];
01422A3D  mov         eax,dword ptr [ebp-14h]  
01422A40  movsx       ecx,byte ptr [eax+72h]  
01422A44  add         ecx,dword ptr [pack_size]  
01422A47  mov         dword ptr [pack_size],ecx  

终于看到问题所在了,在将recbuffer[1]提升为int类型时,编译器使用了movsx指令,而movsx的含义是:

MOVSX说明:带符号扩展传送指令
  符号扩展的意思是,当计算机存储某一个有符号数时,符号位位于该数的第一位,所以,当扩展一个负数的时候需要将扩展的高位全赋为1.对于正数而言,符号扩展和零扩展MOVZX是一样的,将扩展的高位全赋为0.

也即0xd6经过提升为整型后变为0xffffffd6,加上0x100后,正好变成0xd6,造成了高位丢失的假象!

原来问题在于recbuffer的类型为char,这里0xd6是一个负数,将其修改为uchar后,恢复正常。看来在今后的代码中对于类型声明还是要多加注意。

也怪我在调试器中一直将数值显示改为16进制类型,如果显示为10进制,早早可以看到d6是个负数,也不会如此大费周章了。

原文地址:https://www.cnblogs.com/hotzenplotz/p/2921261.html