当前位置: 首页 > news >正文

C++---有符号和无符号整数的位移操作

在C++中,位移操作(左移<<和右移>>)是对整数二进制位的直接操作,但其行为在有符号整数(signed)无符号整数(unsigned) 中存在显著差异。这种差异源于计算机对整数的存储方式(补码)和语言标准对操作的规定,理解这些差异是编写正确位运算代码的关键。

一、位移操作的基本概念

位移操作的本质是将整数的二进制位向指定方向(左或右)移动指定的位数,空出的位由特定规则填充。在C++中,位移操作符的语法为:

  • 左移:a << n 表示将a的二进制位向左移动n位,右侧空出的位补0
  • 右移:a >> n 表示将a的二进制位向右移动n位,左侧空出的位填充规则因整数是否有符号而不同

需要注意的是:

  • 位移的位数n必须是非负整数,且不能大于等于操作数的位数(如32位整数位移32位及以上属于未定义行为);
  • 位移操作的结果类型与左操作数的类型一致(如int位移后仍为int)。

二、无符号整数(unsigned)的位移:逻辑移位

无符号整数的位移是逻辑移位(Logical Shift),即不考虑符号位,仅根据“空位补0”的规则处理,行为在C++标准中是完全明确的。

1. 无符号左移(unsigned << n

左移时,二进制位整体向左移动n位,右侧空出的n位全部补0,左侧超出类型位数的高位被直接丢弃。

举例:假设unsigned int为32位,分析unsigned int a = 0x0000000F(二进制00000000 00000000 00000000 00001111)的左移:

  • a << 1:左移1位后,右侧补0,结果为0x0000001E(二进制00000000 00000000 00000000 00011110);
  • a << 4:左移4位后,右侧补4个0,结果为0x000000F0(二进制00000000 00000000 00000000 11110000);
  • a << 28:左移28位后,高位超出32位的部分被丢弃,结果为0xF0000000(二进制11110000 00000000 00000000 00000000)。

规律:无符号左移n位等价于“a * 2^n”(若结果未超出类型范围)。

2. 无符号右移(unsigned >> n

右移时,二进制位整体向右移动n位,左侧空出的n位全部补0,右侧超出的n位被直接丢弃。

举例:仍以32位unsigned int a = 0xF0000000(二进制11110000 00000000 00000000 00000000)为例:

  • a >> 1:右移1位后,左侧补0,结果为0x78000000(二进制01111000 00000000 00000000 00000000);
  • a >> 4:右移4位后,左侧补4个0,结果为0x0F000000(二进制00001111 00000000 00000000 00000000);
  • a >> 28:右移28位后,左侧补28个0,结果为0x0000000F(二进制00000000 00000000 00000000 00001111)。

规律:无符号右移n位等价于“a / 2^n”(向下取整)。

三、有符号整数(signed)的位移:算术移位为主

有符号整数(如intlong long)在内存中以补码形式存储(最高位为符号位:0表示正数,1表示负数)。其位移行为与无符号不同,尤其是右移,C++标准将其定义为“实现定义”(implementation-defined),但主流编译器(如GCC、Clang、MSVC)均采用算术移位(Arithmetic Shift)规则。

1. 有符号左移(signed << n

有符号左移的行为与无符号左移基本一致:二进制位向左移动n位,右侧空出的n位补0,左侧超出类型位数的高位(包括符号位)被丢弃。

注意:若左移后符号位发生变化(如正数左移后符号位变为1),结果可能超出该类型能表示的范围,此时属于未定义行为(undefined behavior)。

举例:32位int(范围-2^31 ~ 2^31-1):

  • 正数左移:int a = 0x0000000F(15),a << 1 结果为0x0000001E(30),符号位仍为0(合法);
  • 负数左移:int b = -0x0000000F(-15,补码0xFFFFFFF1),b << 1 结果为0xFFFFFFE2(-30),符号位仍为1(合法);
  • 未定义行为:int c = 0x40000000(1073741824),c << 1 结果为0x80000000(-2147483648),符号位从0变为1,属于未定义行为(不同编译器可能有差异)。
2. 有符号右移(signed >> n

有符号右移是最容易产生差异的操作。主流编译器采用算术移位:右侧超出的n位被丢弃,左侧空出的n位补符号位(正数补0,负数补1)。

这种规则的目的是保持位移后数值的“符号一致性”,尤其对负数而言,右移后仍为负数。

举例1:正数右移
int a = 0x0000000F(15,二进制00000000 00000000 00000000 00001111):

  • 符号位为0,右移时左侧补0;
  • a >> 1:结果为0x00000007(7,二进制00000000 00000000 00000000 00000111);
  • a >> 4:结果为0x00000000(0,二进制00000000 00000000 00000000 00000000)。

举例2:负数右移
int b = -0x0000000F(-15,补码0xFFFFFFF1,二进制11111111 11111111 11111111 11110001):

  • 符号位为1,右移时左侧补1;
  • b >> 1:右移1位后,左侧补1,结果为0xFFFFFFF8(-8,二进制11111111 11111111 11111111 11111000);
  • b >> 4:右移4位后,左侧补4个1,结果为0xFFFFFFF0(-16,二进制11111111 11111111 11111111 11110000)。

规律:有符号右移n位对正数等价于“a / 2^n”(向零舍入);对负数等价于“a / 2^n”(向下取整,如-15 >> 1 = -8,而-15 / 2 = -7)。

四、有符号与无符号位移的核心差异对比

操作类型无符号整数(unsigned)有符号整数(signed)
左移(<<)逻辑移位,右侧补0,高位丢弃逻辑移位(同无符号),但可能触发未定义行为
右移(>>)=逻辑移位,左侧补0,低位丢弃算术移位(主流编译器),左侧补符号位
符号影响无符号位,位移后仍为非负符号位不变(算术移位),负数位移后仍为负
应用场景位运算(如哈希、编码)带符号的数值计算(如除法近似)

五、实际开发中的注意事项

  1. 避免对有符号整数进行右移依赖
    由于有符号右移是“实现定义”,若代码需要跨编译器兼容,应避免依赖其行为。如需逻辑右移,可先转换为无符号类型(如(unsigned int)a >> n)。

  2. 负数转换为无符号的妙用
    如之前的toHex函数中,负数转换为unsigned int后,右移变为逻辑移位(高位补0),可正常处理补码的所有位,避免无限循环(若用有符号右移,负数会因补1而永远不为0)。

  3. 警惕位移后的未定义行为

    • 位移位数为负或大于等于类型位数(如32位int移32位);
    • 有符号左移后符号位改变(超出表示范围)。
http://www.dtcms.com/a/336917.html

相关文章:

  • 云原生俱乐部-mysql知识点归纳(1)
  • 《亚矩阵云手机重构出租接单:KVM 虚拟化与边缘计算驱动的设备替代技术路径》
  • 8.18决策树
  • 性能测试(Jemter)
  • grep命令要点、详解和示例
  • 基于nvm安装管理多个node.js版本切换使用(附上详细安装使用图文教程+nvm命令大全)
  • QT第九讲- 控件委托
  • Git智能合并机制深度解析
  • ChatGPT-5 对教育行业的影响与案例研究
  • Qt笔试题
  • 录像视频删除如何恢复?手机电脑的录像恢复技巧
  • 给linux的root磁盘扩容
  • 手游搬砖对云手机的需求有哪些?
  • 机器学习实例应用
  • 获粤港澳大湾区碳足迹认证:遨游智能三防手机赋能绿色通信
  • VLN视觉语言导航(3)——神经网络的构建和优化 2.3
  • 二十八、案例-部门管理-查询
  • Android中flavor的使用
  • 项目实战——矿物识别系统(利用机器学习从化学元素数据中识别矿物,从数据到分类模型)
  • 咨询进阶——解读咨询顾问技能模型
  • NL2SQL 技术深度解析与项目实践
  • Jmeter对图片验证码的处理
  • single cell ATAC(5)使用ArchR聚类
  • CentOS 7.9 部署 filebrowser 文件管理系统
  • 深入解析 Qwen3 GSPO:一种稳定高效的大语言模型强化学习算法
  • 运维命令基础
  • 算法魅力-BFS解决多源最短路
  • PPT生成视频的AI大模型应用技巧
  • 基于51单片机霍尔测速仪表测转速调速系统设计
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频内容理解与智能预警升级(401)