1.整型数据类型
在C语言中 根据数据范围从小到大依次为char、short、int、long、long long
但是对于整型来说 为什么有这么多类型呢
我们得先说字节的本质:
计算机是通过晶体管的开关状态来记录数据 晶体管通常8个为一组 称为一个字节 而晶体管由两种状态 分别是开和关两种状态 一个字节有8个晶体管 所以对应256(2 ^ 8)种状态 每一种状态对应一种数值 所以一个字节可以表示256个数值
在发明C语言的时代 晶体管资源是十分稀缺的 如果想要表示一个0~100的数据 可以用一个字节的类型去表示 何必用两个字节去表示呢
而C语言作为一门强类型语言 他势必要提供类型丰富的数据类型供我们选择 而且我们就算到了现在依然也沿袭了以前的传统 就是用合适的类型装载合适的数据 这(挑选合适的语言)也要求这门语言提供丰富类型的必要性
接下来 我们肯定想要知道C语言中不同类型所占用的字节数 其实这个在C标注中并没有明确规定
他是由不同的编译器和平台有着不同的数据 我们具体可以利用sizeof进行指定类型大小的获取
2.sizeof
我们可以使用sizeof测量各种实体的大小
如果我们在prinf函数中将sizeof作为替换的话 那么对应的占位可以是%d 但是更准确的是%zu
sizeof具体测量的对象可以是:
类型、变量、常量 测量的是指定类型或者指定变量类型或者指定常量类型所占用的字节数
int main(){
int a = 10;
printf("%zu\n", sizeof(int));// 4
printf("%zu\n", sizeof(a));// 4
printf("%zu\n", sizeof(10));// 4
return 0;
}
我们也可以来看一下在clion中C语言每一种整型类型占用的字节数
int main(){
printf("%zu\n", sizeof(char));// 1
printf("%zu\n", sizeof(short));// 2
printf("%zu\n", sizeof(int));// 4
printf("%zu\n", sizeof(long));// 4
printf("%zu\n", sizeof(long long));// 8
return 0;
}
C标准虽然没有明确规定各种整形类型占用的字节数 但是他规定了高级别的取值范围不得小于低级别的取值范围 这对于任何的编译器和平台都需要遵守
3.三位二进制位的取值范围
我们前面讲了 一个字节对应了8个晶体管 一个晶体管对应了两种状态 一个字节对应了2 ^ 8个状态 即256种状态 一种状态对应了一个数值 所以一个字节对应了256个数值
但是我们知道了一个字节对应的数值个数 但是却不清楚具体的数值范围 所以现在我们就来分析一下
由于8位二进制位分析起来属实有点麻烦 所以我们将分析的对象设置为三位二进制位
按照之前的理论 三位二进制位对应了8个数值 但是具体对应的是那八个数值呢
先说结论 0-7
如果不考虑负数的话 那么三位二进制位对应的数值就是0-(2 ^ n) - 1(n表示二进制位的位数)
晶体管的开关状态 二进制 十进制
关关关 000 0
关关开 001 1
关开关 010 2
关开开 011 3
开关关 100 4
开关开 101 5
开开关 110 6
开开开 111 7
但如果要考虑负数的话 我们首先需要来了解一下闹钟理论
一个闹钟一共有12个间隔 每走一个间隔相当于走过一个整点 分别对应12种不同的模式 我们称之为闹钟的模
现在如果想从5点走到12点/0点的话 那么有两种走法 一种是向前走7步 即5 + 7 一种是向后走5步 即5 - 5
第一种走法用公式概括为当前时间 + (闹钟的模 - 当前时间)
第二种走法用公式概括为当前时间 - 当前时间
两种走法都可以达到同样的效果 因此我们可以知道(闹钟的模 - 当前时间)等价于-当前时间
这种做法在二进制中我们称之为用加法等效减法的二进制表示法 即补码表示法 二进制中模为8 即代表8种状态
正数对应的补码就是其自身
正数对应的负数的补码就是(模 - 正数)的二进制
所以如果考虑了负数的话 那么三位二进制位中每一种状态的数值分别是:
(那么就将最高位设置为符号位 不参与数值位的计算 最高位为0时 数值为正 最高位为1时 数值为负)
晶体管的状态 二进制 十进制
关关关 000 0
关关开 001 1
关开关 010 2
关开开 011 3
开关关 100 -4(二进制为(8 - 4)的二进制 所以这个负数为-4)
开关开 101 -3(二进制为(8 - 3)的二进制 所以这个负数为-3)
开开关 110 -2(二进制为(8 - 2)的二进制 所以这个负数为-2)
开开开 111 -1(二进制为(8 - 1)的二进制 所以这个负数为-1)
还有一点需要说明的是 我们在利用二进制做加减法的时候 用多少位进行储存 结果就用多少位进行表示 比如3 + (-3) = 0
011
- 101
1000
由于结果是用三位进行储存 所以只能用三位表示 将最高位抛弃 即000 所以结果是为0
补码还有第二种表示方法:
正数依然等于本身
只不过正数对应的负数的补码的获取方式不一样 其具体方法为:
1.先写出负数对应的正数的二进制
2.遇到第一个1之前全部填0
3.遇到第一个1时 填1
4.遇到第一个1之后 取反
我们在用这个方法来处理三位二进制位中每一个状态下的二进制和十进制分别是什么
晶体管开关状态 二进制 十进制
关关关 000 0
关关开 001 1
关开关 010 2
关开开 011 3
开关关 100 -4
开关开 101 -3
开开关 110 -2
开开开 111 -1
我们可以总结一下了
如果不考虑负数的话 那么三位二进制位的数值范围是:0 - (2 ^ n) - 1
如果考虑负数的话 那么三位二进制位的数值范围是:-(2 ^ (n - 1)) - (2 ^ (n - 1)) - 1
所以C语言中 各种整数类型数据占用的字节数以及取值范围如下图所示:
如果你不打算表示负数的话 那么你可以利用unsigned修饰你的整型变量 但是unsigned修饰的整数也有自己的一套取值范围