有符号数与无符号数的强制类…
2015-07-16 11:08
239 查看
在C语言中有符号数转化为无符号会出现一些问题,先看以下的程序例子:
[cpp] view
plaincopy
int main()
{
char ch[12] = {0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xF
4000
F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00};
unsigned int result = (ch[7] << 8) + ch[6]; // ch[7]为0x0F, ch[6]为0xFF
printf("result(0x%x), ch[7](0x%x), ch[6](0x%x)\n", result, ch[7], ch[6]);
return 0;
}
原本我以为计算结果为
result=0xFFF,但实际的计算结果是result=0xEFF。以下是程序的输出:
原来ch[6]在char转成unsigned
int时由0xff转为了0xffffffff。它的符号位(最高位)为1,在转换成无符号数时将其他位(第9位至第32位)全置为1。所以最后的计算result的结果不0xFFF而是0xEFF。我们来看一下反汇编,就更加清楚了。
[cpp] view
plaincopy
unsigned int result = (ch[7] << 8) + ch[6];
00411C68 movsx eax,byte ptr [ebp-0Dh]
00411C6C shl eax,8
00411C6F movsx ecx,byte ptr [ebp-0Eh]
00411C73 add eax,ecx
00411C75 mov dword ptr [ebp-20h],eax
从上面可以看到使用了movsx指令来进行数据的传输。movsx是带符号扩展传送指令,带符号扩展的意思就是将扩展的那些位都用符号位的值来补全。如8位的数据0xff,转换成32位的数据就是0xffffffff(因为它的符号位为1)。如8位的数据0x3a,转换后的值就是0x3a(因为它的符号们为0)。从反汇编后我们看到转换的过程:
1. 将8位的有符号数扩展成32位的有符号数
2. 对扩展后的32位有符号数进行移位和相加操作
3. 将有符号数以无符号数的形式显示
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们看一下不同字节数的无符号数转换例子:
[cpp] view
plaincopy
int main()
{
unsigned char ch[12] = {0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00};
unsigned int result = (ch[7] << 8) + ch[6];
printf("result(0x%x), ch[7](0x%x), ch[6](0x%x)\n", result, ch[7], ch[6]);
return 0;
}
上面的程序就能输出正确的答案result=0xfff,以下是程序运行的结果:
那为什么这里输出的结果又是正确的呢?我们来看一下反汇编的结果:
[cpp] view
plaincopy
unsigned int result = (ch[7] << 8) + ch[6];
00411C68 movzx eax,byte ptr [ebp-0Dh]
00411C6C shl eax,8
00411C6F movzx ecx,byte ptr [ebp-0Eh]
00411C73 add eax,ecx
00411C75 mov dword ptr [ebp-20h],eax
由8位的无符号数转换成32位无符号数使用了movzx(带0扩展传送指令)。在转换的过程中没有eax的第9至32位置为0,所以最后得到正确的结果。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们将第一个例子改一下,在计算result值的时候先将char类型的ch[7]和ch[6]强制转换为unsigned
char看一下最后得到结果会如何。下面是修改后的代码:
[cpp] view
plaincopy
int main()
{
char ch[12] = {0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00};
unsigned int result = (((unsigned char) ch[7]) << 8) + ((unsigned char)ch[6]);
printf("result(0x%x), ch[7](0x%x), ch[6](0x%x)\n", result, (unsigned char)ch[7], (unsigned char)ch[6]);
return 0;
}
最后的结果就根第二个例子的结果一致,是我们想要的结果。我们再来看一下反汇编后的代码:
[cpp] view
plaincopy
unsigned int result = (((unsigned char) ch[7]) << 8) + ((unsigned char)ch[6]);
00411C68 movzx eax,byte ptr [ebp-0Dh]
00411C6C shl eax,8
00411C6F movzx ecx,byte ptr [ebp-0Eh]
00411C73 add eax,ecx
00411C75 mov dword ptr [ebp-20h],eax
这段反汇编代码与第二个例子的反汇编码一致。由于先将ch[7]强制转为unsigned
char,所以传送指令使用了movzx。
[cpp] view
plaincopy
int main()
{
char ch[12] = {0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xF
4000
F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00};
unsigned int result = (ch[7] << 8) + ch[6]; // ch[7]为0x0F, ch[6]为0xFF
printf("result(0x%x), ch[7](0x%x), ch[6](0x%x)\n", result, ch[7], ch[6]);
return 0;
}
原本我以为计算结果为
result=0xFFF,但实际的计算结果是result=0xEFF。以下是程序的输出:
原来ch[6]在char转成unsigned
int时由0xff转为了0xffffffff。它的符号位(最高位)为1,在转换成无符号数时将其他位(第9位至第32位)全置为1。所以最后的计算result的结果不0xFFF而是0xEFF。我们来看一下反汇编,就更加清楚了。
[cpp] view
plaincopy
unsigned int result = (ch[7] << 8) + ch[6];
00411C68 movsx eax,byte ptr [ebp-0Dh]
00411C6C shl eax,8
00411C6F movsx ecx,byte ptr [ebp-0Eh]
00411C73 add eax,ecx
00411C75 mov dword ptr [ebp-20h],eax
从上面可以看到使用了movsx指令来进行数据的传输。movsx是带符号扩展传送指令,带符号扩展的意思就是将扩展的那些位都用符号位的值来补全。如8位的数据0xff,转换成32位的数据就是0xffffffff(因为它的符号位为1)。如8位的数据0x3a,转换后的值就是0x3a(因为它的符号们为0)。从反汇编后我们看到转换的过程:
1. 将8位的有符号数扩展成32位的有符号数
2. 对扩展后的32位有符号数进行移位和相加操作
3. 将有符号数以无符号数的形式显示
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们看一下不同字节数的无符号数转换例子:
[cpp] view
plaincopy
int main()
{
unsigned char ch[12] = {0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00};
unsigned int result = (ch[7] << 8) + ch[6];
printf("result(0x%x), ch[7](0x%x), ch[6](0x%x)\n", result, ch[7], ch[6]);
return 0;
}
上面的程序就能输出正确的答案result=0xfff,以下是程序运行的结果:
那为什么这里输出的结果又是正确的呢?我们来看一下反汇编的结果:
[cpp] view
plaincopy
unsigned int result = (ch[7] << 8) + ch[6];
00411C68 movzx eax,byte ptr [ebp-0Dh]
00411C6C shl eax,8
00411C6F movzx ecx,byte ptr [ebp-0Eh]
00411C73 add eax,ecx
00411C75 mov dword ptr [ebp-20h],eax
由8位的无符号数转换成32位无符号数使用了movzx(带0扩展传送指令)。在转换的过程中没有eax的第9至32位置为0,所以最后得到正确的结果。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们将第一个例子改一下,在计算result值的时候先将char类型的ch[7]和ch[6]强制转换为unsigned
char看一下最后得到结果会如何。下面是修改后的代码:
[cpp] view
plaincopy
int main()
{
char ch[12] = {0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00};
unsigned int result = (((unsigned char) ch[7]) << 8) + ((unsigned char)ch[6]);
printf("result(0x%x), ch[7](0x%x), ch[6](0x%x)\n", result, (unsigned char)ch[7], (unsigned char)ch[6]);
return 0;
}
最后的结果就根第二个例子的结果一致,是我们想要的结果。我们再来看一下反汇编后的代码:
[cpp] view
plaincopy
unsigned int result = (((unsigned char) ch[7]) << 8) + ((unsigned char)ch[6]);
00411C68 movzx eax,byte ptr [ebp-0Dh]
00411C6C shl eax,8
00411C6F movzx ecx,byte ptr [ebp-0Eh]
00411C73 add eax,ecx
00411C75 mov dword ptr [ebp-20h],eax
这段反汇编代码与第二个例子的反汇编码一致。由于先将ch[7]强制转为unsigned
char,所以传送指令使用了movzx。
相关文章推荐
- Binary Search 二分查找
- animation-circleProgress
- ubuntu12.04 安装配置jdk1.7
- css3中 弹性盒模型布局之box-flex
- 学生信息管理系统
- 【Objective-C】 OC编码规范
- iOS 消息推送实现 APNS
- Android Menu
- 函数参数的传递问题(指针的指针)
- #error
- 共用体
- 结构体大小
- typedef和define有什么区别
- 链表和数组有什么区别
- 简述strcpy、sprintf与memcpy的区…
- 设置地址为0x67a9的整型变量的值为…
- sizeof和strlen的区别
- C中的volatile用法
- stdin、stdout、stderr 的说明
- 使用do{}while(0)的好处