我对C语言移位运算符未定义行为的理解是否正确?
C语言移位运算符未定义行为判定结论
你的理解完全准确,所有规则和示例推导都严格匹配C11/C17标准第6.5.7节对移位运算符的行为约束。
前置定义合理性验证
你给出的三个运算前提完全成立:
x_t:移位运算的左操作数会首先执行整型提升,所有移位运算都基于提升后的类型开展,不会直接在原窄类型上计算N:提升后类型x_t的比特位宽M:x为正值时,提升后二进制表示中最高有效1位左侧的前导零个数,即左移不触发有符号溢出的最大移位位数阈值
左移运算符
<<的未定义行为场景核对 满足任意一项即触发未定义行为,和你总结的完全一致:
- 左操作数
x为负值:哪怕右操作数为0,负数左移也属于UB,标准没有给出任何豁免规则 - 右操作数
y为负值:移位位数不能为负 - 右操作数
y >= N:移位位数大于等于类型总位宽属于UB,注意“32位类型移32位等价于移0位”属于部分编译器的扩展行为,并非标准定义 - 提升后的
x_t为有符号类型,且y >= M:此时左移结果会超出该有符号类型可表示的正整数范围,触发有符号整数溢出,属于UB
右移运算符
>>的行为边界核对 你的总结完全正确:
- 触发未定义行为的场景只有两个:右操作数
y < 0,或者y >= N - 当左操作数
x为负值时,右移的填充规则(补符号位做算术右移/补0做逻辑右移)属于实现定义行为,不属于未定义行为,具体规则由编译器决定。
示例代码行为判定验证
你对示例代码的推导完全正确,测试代码如下:
unsigned short x = 1; x << 31;
- 当运行环境为32位
int、16位short时:unsigned short的取值范围完全落在32位有符号int的表示范围内,x整型提升后为32位有符号int,值为1,此时N=32、M=31,移位位数31等于阈值M,移位后结果会溢出到符号位,触发未定义行为。 - 当运行环境为32位
int、32位short时(常见于部分嵌入式DSP平台):unsigned short的取值范围为0~2^32-1,超出32位有符号int的表示上限,x整型提升后为32位无符号unsigned int,移位位数31小于类型位宽32,无符号左移结果按模2^32计算,行为完全明确,不存在UB。
内容的提问来源于stack exchange,提问作者master_latch
相关产品推荐
相关产品推荐

