C语言中有许多的数据类型
char 字符型 float 单精度浮点数 double 双精度浮点数
short 短整型 int 整形
long 长整型 long long 更长的整形
定义不同的数据类型的意义
区分数据类型有利于编译器决定使用这个类型需要开辟空间的大小以及内存中的数据存储的方式,变相地影响其使用范围。
signed & unsigned
整型数据类型又分为有符号整型和无符号整型
例如:(括号内内容可以省略)
signed char | unsigned char |
(signed)int | unsigned int |
(signed)long (int) | unsigned long (int) |
注:Char short long 都是整型,short 和 long 默认是signed short 和 signed long , 而char是signed 还是 unsigned 取决于编译器 。 |
数据在内存中存储的方式
一、整型
整型在计算机内存中的表示方式有三种:原码,反码和补码。
原码是直接将整数转化为二进制
反码是将整数的原码符号位不变,其他按位取反
补码是将反码加一得到补码
整数在内存中以补码的方式存储。
(整数的三码相同)
这里看到内存窗口中存储的十六进制数字顺序和输入的是相互颠倒的,这里涉及大小端字节序的概念。
大小端字节序:
大端字节序:指整数在存储时,将整数的低字节数位存储在内存的高地址处,将高字节数位存储在内存的低地址处。
小端字节序:与大端字节序相反,指整数在存储时,将整数的低字节数位存储在内存的低地址处,将高字节数位存储在内存的高地址处。
由上图可见,vs2019编译器采用的是小端字节序存储。其中44表示低字节数位,到11数位依次增加。
区分大小端的意义
在计算机系统中,数据存储是以字节为单位的,每个地址单元对应一字节,即8个比特位。但是在C语言中多种数据类型存储的位数不一,另外,对于位数大于8位的处理器,例如16位或者32位的处理器,寄存器宽度大于一个字节,那么就存在着一个如何将多个字节安排的问题。因此就产生了大端存储模式和小端存储模式的概念。
二、浮点型
浮点数的存储方式和整型是云泥之别。
根据国际标准IEEE(电气和电子工程协会),任意一个二进制浮点数可以表示成下面的形式:
(-1)^S * M * 2^E
其中(-1) ^ S表示符号位,当s=0,V为正数;当s=1,V为负数。
尾数 M 表示有效数字,1<= M <2
2^E表示指数位,E 也被称作阶码。
在C语言中,
- 单精度浮点数(float)符号位 S 占一个bit, E 占8个bit,M 占23个bit。
- 双精度浮点数(double)符号位 S 占一个bit,E 占11个bit,M 占52个bit。
阶码的值为E= e + Bias,e是无符号数,Bias为偏置值,等于2^(k-1)- 1 (float为127,double为1023)
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面部分。比如保存1.01时,只保存01,等到读取的时候,再把第一位的1加上去。这样可以节省1位有效数字,提高内存的利用率。
先举个例子,十进制数字5.5的二进制数是101.1,101.1可根据科学计数法写作1.011 * 2 ^ 2按照上面的规则可以得出此处 S = 0, M = 1.011, E = 2 。
偏置值的意义
首先,阶码E是一个无符号整数,但是在科学计数法中E是可以为负数的,因此需要一个中间值来调整E的值,这个值就是偏置值。
再看一个例子,十进制数0.5的二进制数是0.1,可以写成1.0 * 2 ^ -1,阶码E为-1+127 = 126(01111110)。尾数M = 1.0,后面部分为全0,即其二进制表示为
0 01111110 00000000000000000000000
阶码有两个特殊情况:
一、阶码全为0,这时,阶码E的真实值规定为1-127(或者1-1023)
二、阶码全为1,如果有效数字M全为0,表示无穷大,正负取决于符号位S;