C / C++ 左移(<<) 右移(>>) 剖析
例子1 :
char a = 0xF0;
int b = (int)a;
int c = 0xFFFFFFFF;
int d = c << 24;
int e = 0x80000010;
int f = e >> 1;
printf("%d\n", b);
printf("%d\n", d);
printf("%d\n", c);
printf("%d\n", e);
getchar();
例子2 :
char a = 0xF0;
char b = a >> 2;
printf("%d\n", a);
printf("%d\n", b);
getchar();
例子3 :
char a = 0xF1;
char b = a << 4;
char c = 0xF0;
char *b1 = &b;
printf("%d\n", c);
printf("%d\n", (a << 4));
printf("%d\n", b);
getchar();
例子4 :
char a = 0x82;
char b = a >> 1;
printf("%d\n", a);
printf("%d\n", b);
getchar();
例子5 :
char a = 0x42;
char b = a << 1;
char *b1 = &b;
unsigned char c = b;
printf("%d\n", a); //66
printf("%d\n", b); //-124
printf("%u\n", b); //会被提升成unsigned int 0xFFFFFF84
printf("%u\n", (unsigned char)b); //132
printf("%u\n", c); //132
getchar();
例子6 :
char a = 0x10;
char b = a >> 1;
printf("%d\n", a >> 1);//8
printf("%d\n", b); //8
getchar();
注意 :C++ Primer 第五版 有如下说明
首先令左侧运算对象的内容按照右侧运算对象的要求移动指定位数,然后将经过移动的(可能还进行了提升)左侧
运算对象的拷贝作为求值结果。
运算对象可以是带符号的,也可以是无符号的。如果对象是带符号的且它的值为负,那么位运算如何处理运算对象
的“符号位”依赖于机器。而且此时的左移操作可能会改变符号位的值,因此是一种未定义的行为。
注意 :C语言深度剖析有如下说明
左移运算符“<<”是双目运算符。其功能把“<<”左边的运算数的各二进制全部左移若干位,由“<<”右边的数指定移动的
位数,高位丢弃,低位补0。
右移运算符“>>”是双目运算符。其功能是把“>>”左边的运算数的各二进制位全部右移若干位,“>>”右边的数指定移动
的位数。但注意:对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0;而为负数时,符号位为1,
最高位补0或是补1取决于编译系统的规定。Turbo C 和很多系统规定为补1。
个人看法:
其实不光Turbo C,我发现我用的vs2008也是规定为补1,至今我还没有见过补0的系统,所以很多东西还是有迹可循的,
故深入了解后,总结如下,来解释在这类系统下很多开发和调试时候的现象。
个人总结
一 、
先将a转换为补码, 即内存存储方式, 然后小整形一般会提升到4字节(正数补0,负数补1), 然后左移或者右移,然后有
强转发生强转,注意 : 一直都在操作内存中的补码,然后看你想把这个数,按有符号还是按无符号的形式展示出来(printf
打印、赋值或者强转成有符号无符号) :
1.1 用 无符号 的方式展示
编译器直接将补码当成源码去展示
1.2 用 有符号 方式展示
编译器通过查看补码的符号位来判断是正数还是负数,内存中,如果是正数(补码即源码),直接
展示,如果是负数转换为源码后在展示。
二 、
不带符号(非负): 小整形转大整形时左补0, 左移时右补0, 右移时候左补0.
带符号的(负数):先转换成补码(内存方式),小整形转大整形时左补1(注意),左移时右补0, 右移时候左补1(注意).
注意, 大多数机器都左补1,很少机器左补0 (基于是1的补码还是2的补码)
--------------------------------欢迎大家评论和喷--------上述理解有何错误欢迎评论留言---万分感谢-------------------------