一. 简介
前面一篇文章学习了 常见的 C语言基础题,文章如下:
常见C语言基础题说明一-CSDN博客
本文继续上一篇C语言基础题的学习。
二. C语言中 -> 位运算问题
1. 数据在计算机中的存储方式
当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。
对于有符号数最高位是符号位,0代表正数,1代表负数。
对于无符号数,全部都是正数或者0。
计算机中数值都是以补码形式表示的,这样有符号数与无符号数的运算就会统一起来,进行运算时是不会区分有符号和无符号数,最后以相应的类型解释,就得到相应的结果。
原码
有符号整数的二进制编码方式,其中最高位表示符号位,0表示正数,1表示负数。其余位表示数值的绝对值。
负数的原码是在其绝对值的基础上,最高位变为1。
例如,+10的原码为0000 1010,-7的原码为1000 1010。
总结:原码虽然转换方便,但不利于计算。
反码
反码特点:
正数情况下与原码的值不变
负数情况下,符号位不变,但其他部分取反(0变1,1变0)
用代码理解:
这时转换的值=10
原码=0000 1010; 则 反码=0000 1010;
总结:反码并不利于计算,通常用来作为求补码的中间过渡。
补码
在计算机系统中,数值一律用补码来存储
补码特点:
对于正数来说,原码、反码、补码皆相同
对于负数来说,其补码=它的反码加1
补码符号位不动,其他位求反,最后整个 数+1,得到补码
这时转换的值=10
原码=0000 1010;则反码=0000 1010; 则补码=0000 1010;
两个用补码表示的数相加时,如果最高位(有符号位)有进位时,则进位被舍弃。
2. 位运算
无符号数就是存储过程中的最高位符号位不存在,作为数据位使用,而有符号数的最高二进制位为符号位。
无符号数据类型的移位操作
对于unsigned char、unsigned short、unsigned int、unsigned long这些无符号数据类型:
没有特殊要说明的,使用<< 和 >> 操作符就可以。
有符号数据类型的移位操作
对于char、short、int、long这些有符号的数据类型:
对负数进行左移:符号位始终为1,其他位左移
对正数进行左移:所有位左移,即 <<,可能会变成负数
对负数进行右移:取绝对值,然后右移,再取相反数(也就是补齐符号位)
对正数进行右移:所有位右移,即 >>
因为左移操作不会导致符号位出现缺位,所以不考虑符号位,低位补0即可;右移操作会涉及到符号位出现缺位的问题,所以在有符号数的右移操作时要考虑符号位怎么补的问题。
3. 位运算题目(左移)
下面变量进行位移运算后,计算其值:
#include <stdio.h>
int main(void)
{
unsigned int a = 5;
char b = 0x40;
printf("%d\n", a<<1);
printf("%d\n", (char)(b<<1));
return 0;
}
打印结果如下:
分析如下:
unsigned int 类型数据为无符号数据,左移操作直接 左移即可,右边补0。所以,a左移后为 10。
而 char类型为有符号类型(unsigned char类型为无符号类型),char有符号数据可以表示一个字节的数据,能表示的数据范围为 -128~ +127。
char 类型的 b为 0x40,二进制数表示为 0100 0000。当左移一位后,变为 1000 0000(-128的补码),打印结果是 -128。
下面解释一下为什么是 -128?
在八位二进制下,因为有一位是符号位,原码和反码只能表示 0 到 127 ,-0到-127,所以-128不能用原码或反码表示。按这种说法,但由于-128的特殊性,128 因为无法用八位二进制下的原码表示,则 -128的八位二进制下的补码也是不存在的。
但是,为了在数的表示上消除编码映射的不唯一性,所以,通过人为的定义将1000 0000 强制认定为 -128的补码。
因此,-128八位二进制下的原码和反码不存在,而八位二进制下的补码为10000000。
同时,也可以理解为 -128 的补码等于模(即256)减去其绝对值,即256-128=128,而128的二进制表示就是10000000。
综上所述,b 为 有符号 char类型,所以,这里 b 打印出来的值为 -128。