目录
为探究该问题,我们暂且设char sh = 128
有符号char
打印后变成了负数-256
现在有两个问题:
-
为什么是256?
-
为什么是负数
为什么是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语言初学者,可能文笔略有青涩,思路略显幼稚,谨以此记录我对这个问题的一些思考,愿能对各位同道有所启发,望各位谅解,谢谢。