题目
考虑下面的C函数:
int fun1(unsigned word)
{
return (int) ((word << 24) >> 24);
}
int fun2(unsigned word)
{
return ((int) word << 24) >> 24;
}
假设一个采用补码运算的机器上以32位程序来执行这些函数。还假设有符号数值的右移是算术右移,而无符号数值的右移是逻辑右移。
w | fun1(w) | fun2(w) |
0x00000076 | ||
0x87654321 | ||
0x000000c9 | ||
0xedcba987 |
代码
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int fun1(unsigned word)
{
return (int) ((word << 24) >> 24);
}
int fun2(unsigned word)
{
return ((int) word << 24) >> 24;
}
int main()
{
unsigned int w = 0x00000076;
cout << "w = 0x00000076, fun1(w) = " << hex << fun1(w) << ", fun2(w) = " << hex << fun2(w) << endl;
w = 0x87654321;
cout << "w = 0x87654321, fun1(w) = " << hex << fun1(w) << ", fun2w) = " << hex << fun2(w) << endl;
w = 0x000000c9;
cout << "w = 0x000000c9, fun1(w) = " << hex << fun1(w) << ", fun2(w) = " << hex << fun2(w) << endl;
w = 0xedcba987;
cout << "w = 0xedcba987, fun1(w) = " << hex << fun1(w) << ", fun2(w) = " << hex << fun2(w) << endl;
return 0;
}
结果
分析
对于fun1函数来说,(int)((word << 24) >> 24)的执行顺序是
- word << 24 word左移24位
- (word << 24) >> 24 然后右移24位
- (int)((word << 24) >> 24) 最后从无符号数转换成有符号数
对于fun2函数来说,((int) word << 24) >> 24的执行顺序是
- (int) word word 被转换成有符号数
- (int) word << 24 然后左移24位
- ((int) word << 24) >> 24 最后右移24位
相同位模式的有符号数和无符号数,由于编码定义的不同,表示的整数会有所不同。
fun1: 对于无符号数w来说,经过左移24位和右移24位后,所有的数值都会变成0x000000XX(XX=76,21,c9,87)。由于最左边16进制数为0,二进制表示为0000。这样的位模式表示为有符号数值为正,即和无符号数的位模式一样。
fun2: w转换为有符号数后左移操作和无符号数的左移操作是一样的,即都在位最右端填充24个0。
w | (int) word << 24 | ((int) word << 24) >> 24 |
0x00000076 | 0x76000000 [7 -> 0111] | 0x00000076 |
0x87654321 | 0x21000000 [2 -> 0010] | 0x00000021 |
0x000000c9 | 0xc9000000 [c -> 1100] | 0xffffffc9 |
0xedcba987 | 0x87000000 [8 -> 1000] | 0xffffff87 |
由于最左端的位产生了变换, 0xc9000000和0x87000000是负数,所以接下来的右移会是算术右移。而正数的右移依旧是逻辑右移。