数据类型的分类数据类型是数据的基本属性,描述了数据的存储格式和运算规则,不同类型的数据占用着不同大小的存储空间,有着不同的存储格式,能支持的运算和操作也有所不同,因此,在程序中的所有数据,都必须指定其数据类型
-
基本类型
-
整型数据("[]"里面的可以省略)
short [signed] short [int] //在定义一个short类型时,默认为有符号短整型 unsigned short [int] int [signed] int //在定义一个int类型时,默认为有符号整型 unsigned int long [signed] long [int] //在定义一个长整型时,默认为有符号长整型 unsigned long [int] -
字符型数据
char [signed] char //在定义一个char类型时,默认为有符号字符型 数值范围:-128~127 unsigned char //数值范围:0~255
-
-
浮点型数据
float double long double
-
构造类型
- 数组 ([])
- 结构体(struct)
- 共用体(union)
- 枚举类型(enum)
-
指针类型(*)
-
空类型(void)
- 空类型是 void 类型,它主要用于函数的返回类型,函数的参数,指针类型
-
二进制:
-
二级制是计算机技术中广泛采用的一种数制,采用0和1两个数码来表示数,基数为2,进位规则是“逢二进一”,借位规则是“借一当二”。
-
计算机中所有的数据、指令以及符号等都是用二进制代码表示的,一个数在计算机内被表示的二进制形式称为机器数, 该数称为这个机器数的真值。机器数具有以下特点:
-
机器数有固定的位数,因此机器数能够表示的数是在一定范围内的,超过这个范围就会产生“溢出”,因此计算机内部整型数据同样只能表示一定范围内的整数。
-
有符号整数:机器数中采用符号位(一般是最高位,取0或1表示)表示整数的正或负。
无符号整数:没有采用符号位。C语言中定义了有符号整数和无符号整数
-
不管是正整数、负整数、无符号整数,在计算机中都是以补码的形式存储和使用。
-
-
-
有符号整数用最高位表示符号(正或负),其余位表示数值大小
-
无符号整数所有位都用于表示数值的大小
以一个字节(8位)为例(char类型):
无符号整数的最大值为256; (256)10 = (1111 1111)2
有符号整数的最大值为127; (+127)10 = (0111 1111)2
这是因为有符号数中的最高位被移去表示符号位。
符号整数直接用对应的二进制数表示,所有的位都用于直接表示数的大小;
有符号整数在计算机内部表示- 有符号整数在计算机内部用补码表示
- 正数的原码、反码、补码均相同
原码:原码的最高位为符号位,0表示正,1表示负,其余位数表示该数的绝对值。通常用 [X]原 表示X的原码。
- 因为 (17)10 = (10001)2,那么 [+17]原 = 00010001。
- 因为 (39)10 = (100111)2,那么 [-39]原 = 10100111。
- 根据 [X]原 能表示的整数范围公式,可以计算一个字节是原码的表示范围是**[-127,127]**
反码:正数的反码和原码相同,负数的原码就是把其原码除符号位外的各位按位取反(即0变1,1变0)。通常用 [X]反 表示X的反码。
- [+45]反 = [+45]原 = 00101101
- 因为 [-32]原 = 10100000,那么 [-32]反 = 11011111
- 根据 [X]反 能表示的整数范围公式,可以计算一个字节是反码的表示范围是**[-127,127]**
补码:正数的补码与原码相同,负数的补码是在其反码的最低有效位上加1。通常用 [X]补 表示X的补码。
-
[+14]补 = [+14]补 = 00001110
-
因为 [-36]原 = 10100100,而 [-36]反 = 11011011,所以 [-36]补 = 11011100
-
根据 [X]补 能表示的整数范围公式,可以计算一个字节是反码的表示范围是**[-128,127]**
-
补码的意义:采用补码可以将减法变为加法,省去减法器;又由于乘除可通过移位和加减来实现,于是使四则运算在计算机中能转化为对补码的简单移位和相加,大大简化计算机运算部件的电路设计,此外,补码与原码相互转换,其运算过程是相同的。
- 公式如下:[ X+Y ]补 = [ X ]补 + [ Y ]补 和 [ X-Y ]补 = [ X ]补 + [ -Y ]补
具体在操作符章节讲解
大小端-
首先我们来看整型数据在编译器下的内存是怎么存储的?
#include
int main() { int a = 10; //10的补码:00000000000000000000000000001010 转换为十六进制:0000000a int b = -10; //-10的补码:11111111111111111111111111110110 转换为十六进制:fffffff6 return 0; }
-
我们发现,在编译器运行时,存储在内存里面的数据是倒着存储,这是为什么呢?
-
什么是大端小端?
- 大端(存储)模式,是指数据的低位保存在内存的高地址,而数据的高位,保存在内存的低地址中;
- 小端(存储)模式,是指数据的低位保存在内存的低地址,而数据的高位,保存在内存的高地址中;
-
为什么有大小端?
- 在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8个bit。但是在C语言中除了8bit的char类型以外,还有16bit的short类型,32bit的long类型,另外,对于数位大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题,因此就导致了大端存储模式和小端存储模式。
-
设计一个小程序来判断当前机器的字节序
#include
int main() { int a = 1; char* p = (char*)&a; if (*p == 1) { printf("小端"); } else { printf("大端"); } return 0; }
-
根据国际标准IEEE(电气和电子工程协会)754,对任意一个二进制浮点数V可以表示成下面的形式;
-
(-1) ^ S * M * 2 ^ E
-
其中:(-1) ^ S 表示符号位,S=0,V为正数;S=1,V为负数。
-
M 为有效数字,且其范围:1<=M<2;
-
2 ^ E 表示指数位
-
例:
(5.0)10 =(101.0)2,相当于(-1)^0*1.010*2^2 即1.01*2^2;可以得出:S=0;M=1.01;E=2。
(-5.0)10 =(-101.0)2,相当于(-1)^1*1.010*2^2 即-1.01*2^2;可以得出:S=1;M=1.01;E=2。
-
-
-
IEEE 754 规定
- 对于32位的浮点数(即float类型),最高位是符号位S,占用一个bit位;接着是指数E,占用8个bit位;剩下的是有效数字E,占用23个bit位。
- 对于64位的浮点数(即double类型),最高位是符号位S,占用一个bit位;接着是指数E,占用11个bit位;剩下的是有效数字E,占用52个bit位。
-
IEEE 754对有效数字M和指数E,还有一些特别规定
-
对于有效数字M:
前面我们讲过,1<=M<2,也就是说 ,M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分
例如:保存1.01时,只保存01,等到读取的时候,再把第1位加上去,这样做的目的是,节省1位有效数字。
以32位浮点数为例,留给M只有23位,将第一位的1舍去之后,就可以保存24位有效数字了。
-
对于指数E:
-
IEEE 754规定:在存入内存时,E的真实值必须在加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。
例如:2^10中E是10,所以保存成32浮点数时,必须保存为10+127=137,即10001001;
-
指数E从内存中取出还要分为3中情况:
-
E不全为0或不全为1:
指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
-
E全为0:
浮点数的指数E等于1-127(或者1-1023),即为真实值。
有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数,这样做是为了表示±0,以及接近于0很小的数字
-
E全为1:
如果有效数字M全为0,表示±无穷大(正负取决于符号位)
-
-
-
-
例:
-
例1:
int main() { float f = 5.5f; //转换为二进制:101.1 //表示成:(-1)^0 * 1.011 * 2^2 S=0;M=1.011;E=2; //存入内存:S存入0 M存入011 E存入2+127=129 //内存区域:0 10000001 01100000000000000000000 (二进制) //内存区域:40 b0 00 00 (十六进制)而这个就是编译器下内存中展示的 return 0; }
-
例2:
-
#include
int main() { int n = 9; float* pFloat = (float*)&n; printf("n的值为:%dn", n); printf("pFloat的值为:%fn", *pFloat); *pFloat = 9.0; printf("num的值为:%dn", n); printf("*pFloat的值为:%fn", *pFloat); return 0; }//编译结果: //n的值为:9 //pFloat的值为:0.000000 //num的值为:1091567616 //*pFloat的值为:9.0 - 为什么会出现这样的结果?



