C学习:移位幻影之左移一个负数,会发生什么?

C学习:移位幻影之左移一个负数,会发生什么?

问题背景


C语言中,移位是个简单的问题,但又是个高风险的问题。

简单在于,大部分场景都可以理解为乘或除2的幂。风险在于,C语言中对有符号数的移位与无符号数的移位异常场景,未定义:

  • 不同位宽转换时的移位过程如何处理?
  • 有符号数的左右移动,是逻辑移位,还是带符号移位?
  • 无符号数的移动中,移动数为负或超过了符号位宽如何处理?

前两问题中,在《C学习:无符号有符号数的移位问题分析总结》和《C学习:隐藏在负数移位过程中的bug》有过一些探讨,这里就第最后一个问题做一些小结。

无符号数移位问题


之前在《C学习:一个百思不得其解的无符号数移位问题》,也初步聊过,但无法解释下面这个问题。

1<<-1,对无符号数如1左移-1位会发生什么?

照例,先问下AI大模型看它如何应对。Prompt提问是:C语言中,执行这段语句:int b = 1 << -1, 会发生什么?

Copilot回答如下:

在C语言中,执行语句 int b = 1 << -1; 会导致未定义行为。原因如下:

  1. 位移操作符<< 是左移操作符,用于将一个整数的二进制位左移指定的位数。
  2. 负数位移:标准C语言不允许负数位移。位移操作的位数必须是非负整数。

因此,1 << -1 是非法的,会导致未定义行为。这意味着程序的行为是不可预测的,可能会导致程序崩溃或产生错误的结果。

我理解,不可预测指的是该操作的结果有多义性,具体行为取决于编译器处理,比如可能结果:

  • 为0,编译器翻译为右移1位,1>>1
  • 直接报错返回,编译器直接返回运行错误码

我的环境,跑的结果是0,会告警,但不会报错。错的是将其作为除数,导致浮点除零。但编译器也没中断,而是将结果存为一个极小值,继续运行。

有符号数移位操作使低位置零问题


t = (t << 8) >> 8,此代码中,t为有符号数int类型,移位结果是否固定?

显然,前文说过,有符号数移位是未定义行为,可能是算术,也可能是逻辑移位。但多数编译器,是使用的算术移位,即带符号移位。

所以,一般场景而言,该行代码能实现有符号数的低8位比特置零的效果。

但是,假如我们不允许对有符号数进行移位,该如何实现有符号数低8位置零操作呢?

容易想到的是,C语言中可通过除法这样实现:t = t / 256 * 256

扩展思考的是,可否不用除法,将有符号数移位过程等价转换到无符号数的位操作上去,从而更高效的实现?

c 复制代码
   /*  Write C code in this online editor and run it. */

    printf("Hello, World! \n");


    int num = -10;
    
    unsigned int numVer = num;
    
    printf("0x%x\n", numVer);


    num = -33554432; // -2^25()
    
    printf("0x%x\n", num);
    
    int num_shift = (num << 8) >> 8;
    
    printf("0x%x\n", num_shift);

仍存疑中。

相关推荐
cwtlw11 分钟前
PhotoShop学习03
笔记·学习·photoshop
西元.17 分钟前
线程等待与唤醒的几种方法与注意事项
java·开发语言
辰熤✔24 分钟前
MQTT报文类型
c语言·网络
独好紫罗兰25 分钟前
洛谷题单2-P5717 【深基3.习8】三角形分类-python-流程图重构
开发语言·python·算法
落榜程序员26 分钟前
Java基础-25-继承-方法重写-子类构造器的特点-构造器this的调用
java·开发语言
forestsea32 分钟前
Java 应用程序CPU 100%问题排查优化实战
java·开发语言
啊阿狸不会拉杆33 分钟前
第十八章:Python实战专题:北京市水资源数据可视化与图书馆书籍管理应用开发
开发语言·python·信息可视化·用户界面
阿ฅ( ̳• ε • ̳)ฅ37 分钟前
C#窗体应用程序连接数据库
开发语言·数据库·c#
学习同学39 分钟前
C++进阶知识复习 1~15
java·开发语言·c++
职业考试资料墙1 小时前
如何报名参加登高架设作业考试?
学习·考试·题库·考证