位操作符左移问题(<<)如果char类型左移后位数超出一字节如何打印?

目录

有符号char

现在有两个问题:

为什么是256?

为什么是负数

无符号char


为探究该问题,我们暂且设char sh = 128

有符号char

 

打印后变成了负数-256

现在有两个问题:

  1. 为什么是256?

  2. 为什么是负数


为什么是256?

首先,char类型占一个字节,无法表示256,那么它应当是自动转化为了较大的类型

查阅资料知:

当右移的运算数是byte 和short类型时,将自动把这些类型扩大为 int 型。

——移位运算符<< >> >>>的使用

我们有理由怀疑char类型也是自动转换为了int类型

我们先讨论第二个问题,稍后再讨论这个问题


为什么是负数

其实,我们在一开始设sh为128是有风险的,因为有符号类型的char的表示范围是-128~127

为什么会这样?

表示有符号数的时候,我们会有一个符号位,这个位是二进制数的最高位,用0来表示正数,用1来表示负数。剩下的位,如果本身是正数,则不变;如果是负数,则将它的绝对值的表示转换为二进制补码(实质上,一般无需首先确定符号位,因为负数的第一位一般来说补码都是1)(具体详见佛罗赞的《计算机科学导论》)

C语言中,有符号数与无符号数主要是由于是高位是否代表符号(正、负数)来决定的。有符号数是最高位(二进制位)代表符号,1代表是负数,0代表是正数,不管是正数还是负数都是以补码的形式存储与使用的。

也就是说,我们让sh = 128,最终导致它发生溢出!

就像一个环一样,从127在踏出一步,就到了-128(因为计算机会将溢出的位数直接舍弃,保留剩下的位数,具体详见佛罗赞的《计算机科学导论》)

而这时,sh的绝对值的二进制表示应当是1000 0000(即0111 1111 + 1),其中第一位表示大小的同时表示符号为负,因此同时应该将其转换为补码(补码不代表它的数值大小)

如果此时向左移位,如果它不能自动转换为int类型,那么应该显示为0;如果可以,应当显示为-256,即0001 0000 0000

为进一步证实这一点,我们将左移后结果强制转换为char

 

结果如我们所料,是0


那么,我们回到第一个问题,如何证明是自动转换为了int而不是其他类型?

其实方法很简单,那就是利用int类型和其他类型能保存的位数的不同。

如上所言,此时-256是以补码形式表示的,如果此时将它强制转换为无符号数,它应当是一个很大很大的数,那么我们就可以根据结果的大小来判断是否为int型

我们期望的值是1111 1111 1111 1111 1111 1111 0000 0000

而实验所得值是:

 

结果如我们所愿。

并且将转换说明换成%lu也没有影响:

如果sh一开始的值稍小一点,为127的话,结果就会天差地别:

这是因为正数和负数在补码(two's complement)中的表示天差地别。

这就证明了它会自动转换为int类型(当然,我不知道不同编译器会不会对这种自动转换有影响,但至少在VS 2019中是这样的)


无符号char

没什么好说的,比较简单,基础的自动转换。

 


注:笔者是C语言初学者,可能文笔略有青涩,思路略显幼稚,谨以此记录我对这个问题的一些思考,愿能对各位同道有所启发,望各位谅解,谢谢。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值