C语言入门系列:有符号整数的左移、右移

文章目录

左移(<<)

将一个操作数的所有位向左移动指定位数,右侧空出的位用0填充。

c 复制代码
int h = 0b0001; // 1 in decimal
int result = h << 2; // 0b0100, which is 4 in decimal

这里,h左移两位后,原来的1变成了100,即十进制的4。

左移运算符相当于将运算数乘以2的指定次方,比如左移2位相当于乘以4(2的2次方)。

上述案例左移2位,相当于原数1乘以4,所以结果是4。

当有符号整数进行位运算"左移(<<)"时,规则是"符号位不变,移出位丢弃,空出位补0"。即正整数左移N位时低位依次填充N个0,负整数左移N位时低位依次填充N个0。

例如:

clike 复制代码
0000 0010 << 1 = 0000 0100  
0000 1010 << 2 = 0010 1000 
1000 0010 << 1 = 1000 0100   
1000 1010 << 3 = 1001 0000

左移不改变有符号整数的符号位。

左移溢出怎么办?

注意:左移的位数超过该数值类型的最大位数时,编译器会用左移的位数去模类型的最大位数,然后按余数进行移位。

如:

clike 复制代码
int i=1; //设int为32位
i=i<<33; // 33%32=1,相当于 i=i<<1

如下代码:

clike 复制代码
int main()
{
    int num = 1;
    int num2 = num << 33;
    printf("左移前num=%d\n", num);
    printf("num左移33位后num2=%d\n", num2);
    return 0;
}

运行结果:

右移(>>)

将一个操作数的所有位向右移动指定位数,对于有符号整数,左侧空出的位用符号位填充(即保持符号不变),对于无符号整数,用0填充。

c 复制代码
int i = 0b1010; // 10 in decimal
int result = i >> 1; // 0b0101, which is 5 in decimal

这里,i右移一位后,变成了0101,即十进制的5。

右移运算符相当于将运算数除以2的指定次方,比如右移1位就相当于除以2(2的1次方),所以上述示例右移一位,相当于10除以2,结果是5。

但是,对于负数,右移位操作存在一个左移位操作不曾面临的问题:从左边移入的位,可以选择两种方案。

算术右移(Arithmetic Shift Right, ASR):

当对负数进行算术右移时,最高位(即符号位)保持不变。

这意味着,如果一个负数的最高位是1(表示负数),那么在右移过程中,空出来的高位会被符号位的值填充,即填充1。

这样可以确保右移后得到的仍然是一个负数,且保持了原来数的符号不变。

例如:

clike 复制代码
0000 0010 >> 1 = 0000 0001  
0000 1010 >> 2 = 0000 0010 
1000 0010 >> 1 = 1100 0001   
1000 1010 >> 3 = 1111 0001

这种处理方式适用于需要保持负数符号的场景。

逻辑右移(Logical Shift Right, LSR):

逻辑右移对负数的处理与无符号整数相同,即高位统一填充0。

这种方式不考虑原数的符号,纯粹是将所有位向右移动,高位补0。

clike 复制代码
0000 0010 >> 1 = 0000 0001  
0000 1010 >> 2 = 0000 0010 
1000 0010 >> 1 = 0100 0001   
1000 1010 >> 3 = 0001 0001

这样做的结果是,无论正数还是负数,右移的结果都是正数。

C语言标准并没有明确规定右移负数的具体行为,因此不同平台和编译器可能会有所不同。

一般情况下,C编译器会采用算术右移,以保持负数的符号性,但这并不是绝对的,特别是在某些特殊环境下或通过特定编译器选项配置。

对于有符号值,到底时采用逻辑移位还是算数移位取决与编译器,不能保证所有的编译器采用同样的方式。

因此 ,最佳实践是右移运算符不用于有符号数。

相关推荐
wuyk5555 分钟前
嵌入式驱动开发:量产级工程化实战(第9篇)——低功耗下的通信可靠性
c语言·驱动开发·stm32·单片机·嵌入式硬件
学逆向的33 分钟前
C 突破编译器限制
c语言·开发语言·网络安全
jimy11 小时前
C++ 虚函数表:基类和派生类共用一张 vtable 吗?
开发语言·c++
爱吃提升1 小时前
Dev-C++ 5.11 C++断点调试完整教程
开发语言·c++
夜晚回家1 小时前
Python 原始字符串详解 | r 前缀到底让什么不再转义
开发语言·python
陈年老古董1 小时前
PyQt5 入门指南:环境搭建、PyCharm 外部工具配置与登录界面实战
开发语言·qt·pycharm
看浪的路人1 小时前
第7讲:大模型后端服务化——Go 实现高并发 LLM Proxy / Router / Fallback
开发语言·后端·golang
iCxhust1 小时前
Matlab求解发电机的极限切除角
开发语言·算法·matlab·电力系统
zhanghaha13142 小时前
Qt 类完整例程【逐词拆解 + 逐步骤执行保姆教程】
开发语言·qt
endeavor122 小时前
can总线(五)
c语言·stm32·单片机·can