(C 语言)类型提升的问题
今天在工作中发现了一个和类型相关的问题 .
代码如下:
Declaration:
uint32 cursor;
uint16 i;
uint16 old_str_len = 0;
uint16 new_str_len = 0;
Code:
if (cursor >= i + old_str_len)
cursor += new_str_len - old_str_len;
else if (cursor > i)
cursor = i + new_str_len;
在使用中,我无意中把 cursor 类型从 uint16 提升到 uint32 位。编译通过后把 target flash 到手机中。当运行到这段代码时,手机总是会重启。当时百思不得其解。后来发现只要把 cursor 类型从 uint32 改回 uint16 就可以了。
经过分析,原因如下:
代码 cursor += new_str_len - old_str_len; 中 new_str_len - old_str_len 的结果是个负数,假定 new_str_len = 1 , old_str_len = 2. 那么 new_str_len - old_str_len = 0XFFFF.
Cursor 是 32 位的,再和 cusor 做计算的时候,需要把 new_str_len - old_str_len 的值提升到 32 位,那么这个值就是 0X0000FFFF, 这时 Cursor + 0X0000FFFF 显然不是我们想要的结果。
如果把 cursor 改回 16 位,那么 Cursor + 0XFFFF 就相当于 Cursor – 1 ;此时得到的结果才是我们要的结果。
同样的问题在 VC 上确并不会发生,这是和芯片位数相关的一个问题。在 VC 上,芯片是 32 位的,在计算的时候
cursor += new_str_len - old_str_len;
new_str_len - old_str_len 是按照 32 位来计算的,得到的结果先存在寄存器中也是 32 位的。这样计算结果就不会出错。
而在我使用的平台中,芯片是 16 位, new_str_len - old_str_len 得到的临时结果也是 16 位的,再和 cursor 计算的时候,就存在了一个位提升的问题。
我们来看看 VC 中的一个例子
uint16 i = 2;
00458DB8 66 C7 45 EC 02 00 mov word ptr [i],2
uint16 j = 1;
00458DBE 66 C7 45 E0 01 00 mov word ptr [j],1
uint16 x ;
uint32 y;
y = 3;
00458DC4 C7 45 C8 03 00 00 00 mov dword ptr [y],3
x = j - i;
00458DCB 0F B7 45 E0 movzx eax,word ptr [j]
00458DCF 0F B7 4D EC movzx ecx,word ptr [i]
00458DD3 2B C1 sub eax,ecx
00458DD5 66 89 45 D4 mov word ptr [x],ax //在实际的运算是 32位的,只是在把运算结果赋给目标变量的时候才裁剪为 16位的值。
y += j - i;
00458DD9 0F B7 45 E0 movzx eax,word ptr [j]
00458DDD 0F B7 4D EC movzx ecx,word ptr [i]
00458DE1 2B C1 sub eax,ecx
00458DE3 03 45 C8 add eax,dword ptr [y]
00458DE6 89 45 C8 mov dword ptr [y],eax