目录
整型的分类
signed char
unsigned char
signed short
unsigned short
signed int
unsigned int
signed long
unsigned long
signed表示有符号的整型,unsigned表示无符号的整型,一般情况下signed可以省略。
原码、反码、补码
对于有符号的整型,三种表示方法都分为符号位和数值位两个部分,符号位为开头的1位,符号位为0表示正数,符号位为1表示负数。需注意的是,正数的原码、反码、补码相同。
原码:将数值按正负转化为二进制,该二进制数即为该数值的原码。
反码:原码的符号位不变,数值位按位取反即可得到反码。
补码:反码+1即可得到补码。
举个例子:
一个int类型占用4个字节,共32位(1byte = 8bit)
int x = 10;
//x的原码为:00000000 00000000 00000000 00001010
//因为x是正数,所以x的反码和补码与其原码相同
int y = -10;
//y的原码为:10000000 00000000 00000000 00001010
//y的反码为:11111111 11111111 11111111 11110101
//y的补码为:11111111 11111111 11111111 11110110
数据是以补码的方式存放在内存中的,所以在整型表达式计算的时候使用的并非原码,而是使用补码进行计算。
整型的取值范围
以signed char举例
signed char
00000000 ---> 0
00000001 ---> +1
00000010 ---> +2
...
01111111 ---> +127
10000000 ---> -128(规定)
10000001 ---> -127
...
11111101 ---> -3
11111110 ---> -2
11111111 ---> -1
所以signed char的取值范围为:-128~127,而unsigned char就简单了,8位一共256种情况,所以unsigned char的取值范围为:0~255。
大端、小端
大端存储模式:数据以字节为单位,数据的低位存放在高地址处,数据的高位存放在低地址处。
小端存储模式:数据以字节为单位,数据的低位存放在低地址处,数据的高位存放在高地址处。
举个例子:
int x = -20;
//x的原码为:10000000 00000000 00000000 00010100
//x的反码为:11111111 11111111 11111111 11101011
//x的补码为:11111111 11111111 11111111 11101100
//x的补码用16进制表示为:ff ff ff ec
如上图所示,我们发现x的低位ec存放在了低地址处,高位存放在了高地址处,这便是小端存储。
那如何写一段代码来判断当前机器是大端还是小端呢?我们可以用char类型的指针来指向int类型的数据的地址,这样指针解引用时访问的那一个字节的空间内容会因为大小端产生差异。
int x = 1;
char* y = &x;
if (*y == 1)
printf("小端\n");
else
printf("大端\n");
x的补码是00000000 00000000 00000000 00000001,低位是1,如果低位放到了int起始的那个字节,也就是指针指向的那个字节,也就代表把低位的1放到了低地址处。那么指针解引用为1便是小端存储模式。而如果把高位的0放在了起始的那个字节,那便是大端存储模式。
截断、整型提升
我们都知道char存放的是字符,但如果我们把硬是数字赋值给char会发生什么?没错,截断!举个例子:
char x = -10;
//x的原码为:10000000 00000000 00000000 00001010
//x的反码为:11111111 11111111 11111111 11110101
//x的补码为:11111111 11111111 11111111 11110110
//但x的类型是char,只有8位,所以从数据的低位发生截断
//截断后:11110110
而当我们用x进行计算时,因为C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。比如下面这串代码:
char x = -10;
//截断后:11110110
int y = 20;
//y的补码:00000000 00000000 00000000 00010100
int z = x + y;
//计算时x需要整型提升,因为x的类型是有符号的char,所以整型提升的时候高位补符号位
//x提升后:11111111 11111111 11111111 11110110
//y的补码:00000000 00000000 00000000 00010100
//z的补码:00000000 00000000 00000000 00001010
//因为z为正数,所以z的原码与补码一致,计算结果为z=10
乍看上去整型提升似乎没啥存在感,不就是-10 + 20 = 10嘛,那下面例子整型提升的存在感就很强了:
char x = 1;
printf(" x:%u\n", sizeof(x));//sizeof求类型所占字节大小
printf("x+0:%u\n", sizeof(x+0));
short y = 1;
printf(" y:%u\n", sizeof(y));
printf("y+0:%u\n", sizeof(y+0));
结果如下:
当x、y未参与计算时,为其本来的类型大小,char是1个字节,short是2个字节。但当x、y参与计算,就会发生整型提升,变为int类型的大小,也就是4个字节。还有要补充的一点就是,整数提升时高位补什么取决于该数值的类型,若是有符号数,则提升符号位,若不是,则提升0。