(转载)http://hi.baidu.com/fanggai/item/1c44f1f2e3d81dc4a935a266
关键词:C语言,右移运算符,右移运算符+取反运算符,算术右移
环境:VC6.0
由一段C语言面试题引起,对其中的某些运算结果有疑惑,写了段小程序测试了下。
由下面的程序和输出结果得出一些结论:
1.位运算符不改变原变量的值,即无副作用;
2.进行取反运算~时,编译器会将char型转换为int型进行计算(VC6.0,其他编译器未测试),这时要特别注意,一般int型字节数比char型多,转换后高位为0,取反后为1,若后续有右移运算,则会将这些1移入,影响计算结果。
如
unsigned char a = 0xA5;
unsigned char b = ~a>>4;
printf("b= %d \n", b);//245
a = 0xA5取反后2进制表示为01011010,若按该数值进行右移运算>>4(无论是逻辑右移还是算术右移),则结果应为00000101,对应的十进制数应为5,而输出结果为245,这是为什么呢?
其实应该是这样的:
1)将a转换为int型(4字节),即00::0010100101(32位,::表示20个0);
2)将a取反,则变为11::1101011010(32位,::表示20个1);
3)a开始右移,右移4位,然后截取低8位赋值给b,即11110101,对应的十进制数值为245。
附测试程序如下:
#include <stdio.h>
int main()
{
unsigned char a = 0x11;//初始值最高位为0
unsigned char b = (~a)<<4;
printf("b= %d \n", b); //224
b = ~a<<4;
printf("b= %d \n", b); //224
b = ~(a<<4);
printf("b= %d\n",b); //239
b = (~a)>>4; //~优先级高于>>
printf("b= %d\n",b);//254
b = ~(a>>4);
printf("b= %d\n",b);//254
b = ~a>>4; //
printf("b= %d\n",b);//254
a = 0xA5; //初始值最高位为1
b = ~a>>4;
printf("b= %d \n", b);//245,
b = (~a)>>4;
printf("b= %d \n", b);//245,
a = 0xA5;
b = a>>4; //没有取反运算
printf("b = %d \n", b); //10,
return 0;
}
3.判断VC6.0是逻辑右移还是算术右移
#include <stdio.h>
int main()
{
int i = 0x80028002;
int j = i>>31; // int型变量可以做移位运算
printf("j= %d \n", j); // -1,由此判定右移时还是算术右移
}
分析过程:
上述程序输出j = -1,则推断为算术右移。
1)i = 0x80028002的二进制表示1000 0000 0000 0010 1000 0000 0000 0010;
2)由于最高符号位为1,i右移31位,i的二进制表示1111 1111 1111 1111 1111 1111 1111 1111;
3)i的原码表示1000 0000 0000 0000 0000 0000 0000 0001,故i的值为-1。
欢迎讨论。
例子:
#include <stdio.h> int main(int argc, char** argv) { unsigned char a = 0xa5; unsigned char b = (~a) >> 4; char c = 0xa5; char d = (~c) >> 4; printf("%d\n", b); printf("%d\n", d); printf("\n"); printf("%d\n", sizeof(~a)); return 0; }
程序输出:
b = ~a >> 4的运算顺序肯定是a先取反,但a是字符型,进行取反运算的时候编译器自动转换为int型,于是a变成int型。
然后取反,再进行右移4位操作,就可以得到这个结果了。其实用sizeof(~a)就可以检测出~a之后是int型。
总结:对char、unsigned char取反时,现将其提升为int类型,然后再进行取反。