目录
一、数据存储
基本数据类型
char // 字符数据类型 1个字节short // 短整型 2个字节int // 整形 4个字节long // 长整型 4个字节long long // 更长的整形 8个字节float // 单精度浮点数 4个字节double // 双精度浮点数 8个字节
二、数据存储类型分类
1、整型家族
char : 取值范围unsigned char 0~255signed char -128~127short:unsigned short [ int ] 0~65,535signed short [ int ] -32768~32,767int:unsigned int 0~4,294,967,295signed int -2,147,483,648~2,147,483,647long:unsigned long [ int ] 0~4,294,967,295signed long [ int ] -2,147,483,648~2,147,483,647
2、浮点型家族
floatdoublelong double
3、自定义类型
结构体类型 struct枚举类型 enum联合类型 union
4、指针类型
char*
short*int*long*long long*float*double*struct* pcvoid*
5、空类型
void 空类型(用于函数的返回类型、函数的参数、指针类型)
三、整型家族在内存中的存储
1、大小端的理解
数据是从低位向高位进行存储,但在数据的存储过程中,数据在从低位向高位的存放顺序不一,从而形成了两种数据存放的模式:大端模式和小端模式
大端(存储)模式:是指数据的低位字节内容保存在内存的高地址中,而数据的高位字节内容保存在内存的低地址中;小端(存储)模式:是指数据的低位字节内容保存在内存的低地址中,而数据的高位字节内容保存在内存的高地址中。
2、大小端直观内存显示图:
3、大小端存储的方式如何检测
4、整型家族内存中的存储方式
整型家族在内存中的存储是以补码的方式进行存储,再讲他们的存储之前先讲一下什么是原码反码补码。原码反码补码在32位机上是32比特位,在64机位上是64比特位。
a、原码反码补码:
①原反补码中:第一位符号位,其余几位为数据值位。
②原码反码补码
正数的符号位为0,原码的数值位为该数,原码反码补码相同
负数的符号位为1,原码的数值位为该数,反码符号位不变数值位取反,补码为反码+1
③该知识为计算机组成原理中的相关知识,原码转换为补码总结为:
正数的原反补码相同,负数符号位不变。
补码为原码从右边数到第一个1位置不变,数值位往左到符号位后全部取反。
b:数据在内存中的存储
①实例一
int main()
{
//整型家族
//10000000 00000000 00000000 00010100 原码
//11111111 11111111 11111111 11101100 补码
//ff ff ff ec
unsigned int i = -20;
//00000000 00000000 00000000 00001010 原码
//00000000 00000000 00000000 00001010 补码
//00 00 00 0a
int j = 10;
printf("%d\n", i + j);//%d打印的是有符号的数
//i+j
// 补码相加
//11111111 11111111 11111111 11101100 i
//00000000 00000000 00000000 00001010 j
//11111111 11111111 11111111 11110110 i+j补码
//10000000 00000000 00000000 00001010 i+j原码
//以有符号的形式打印就是补码转为原码(数据在内存中以补码存储,打印有符号数值时转为原码)
//结果-10
printf("%u\n", i + j);//%u打印的是无符号的数
//i+j
// 补码相加
//11111111 11111111 11111111 11101100 i
//00000000 00000000 00000000 00001010 j
//11111111 11111111 11111111 11110110 i+j补码
//以无符号的形式打印就是直接打印补码(首元素1不再表示符号位)
//结果4294967286
return 0;
}
②实例二
int main()
{
//因为i是无符号数,所以在循环中一直是大于等于0,进入死循环
unsigned int i;
for(i = 9; i >= 0; i--)
printf("%u\n",i);
}
③实例三
int main()
{
//10000000 00000000 00000000 00000001 原码
//11111111 11111111 11111111 11111111 补码
//char类型只取1个字节,内存中存放ff(11111111)
char a = -1;
signed char b = -1;
//a,b是有符号的char,%d输出时会整型提升前面补符号位1
//11111111 11111111 11111111 11111111
//转为原码为10000000 00000000 00000000 00000001打印为-1
unsigned char c = -1;
//c是无符号char,整型提升前面补0
//00000000 00000000 00000000 11111111无需转为原码直接打印255
printf("%d %d %d\n", a, b, c);
return 0;
}
a,b,c内存中的存放
运行结果
④实例四
int main()
{
//128
//00000000 00000000 00000000 10000000 原码
//00000000 00000000 00000000 10000000 补码
//存入内存10000000
char a = 128;
//-128
//10000000 00000000 00000000 10000000 原码
//11111111 11111111 11111111 10000000 补码
//存入内存10000000
char b = -128;
//a整型提升为
//11111111 11111111 11111111 10000000 补码
//10000000 00000000 00000000 10000000 转为原码
//以%d输出原码
//以%u直接输出补码
//
//b整型提升为
//11111111 11111111 11111111 10000000 补码
//10000000 00000000 00000000 10000000 转为原码
//以%d输出原码
//以%u直接输出补码
printf("%d %d\n", a, b);
printf("%u %u\n", a, b);
return 0;
}
运行结果
char类型在内存中的存储范围为-128~127,上图中char类型的128存入内存中相当于127+1=-128
⑤实例五
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
//有符号char类型的取值范围是 -128~127
//-1 -2 -3 -4 ... -128 127 126 ... 1 0
//128 + 127 = 255
}
printf("%d", strlen(a));//'\0'结束
return 0;
}
运行结果
四、浮点型家族在内存中的存储
1、IEEE的存储规则
在讲浮点型在内存中的存储前首先要了解什么是IEEE规则
IEEE 754 规定:对于32位的单精度浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的双精度浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
64位:
根据国际标准IEEE754,任意一个二进制浮点数V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^S: 表示符号位,当 S=0 , V 为正数;当 S=1 , V 为负数。M: 表示有效数字,大于等于 1 ,小于 2 。2^E: 表示指数位。
IEEE 754 规定,在计算机内部保存 M 时,默认这个数的第一位是1,因此可以被舍去,只保存后面的部分,比如保存1.625时只保存625,取出来时,小数点前自动补1。 这样就可以节省一个比特位,增加精度。以 32 位浮点数为例,留给M 只有 23位,将第一位的 1 舍去以后,等于可以保存 24 位有效数字,64位浮点数同样如此。
E是一个无符号的整数如果 E 为 8 位,它的取值范围为 0~255;如果 E 为 11 位,它的取值范围为 0~2047 。但是,我们知道,科学计数法中的E 是可以出现负数的,所以IEEE754 规定,存入内存时 E 的真实值前必须再加上一个中间数。对于 8 位的 E ,这个中间数是127 ;对于 11 位的 E ,这个中间数是1023 。比如, 2^13中 的 E 是 13 ,所以保存成 32 位浮点数时,必须保存成 13+127=140 ,即10001100 。
当E为全0时,即真实值为-127( 或者-1023),2^-127(或者 -1023)是一个无限接近于0的数。当E为全1时,即真实值为128( 或者1024),2^128(或者 1024)是一个趋于无穷大的数。
2、浮点数在内存中的存储
int main()
{
//浮点型家族
//9
//00000000 00000000 00000000 00001001 原码反码补码相同
int n = 9;
float* pFloat = (float*)&n;
//取原码00000000 00000000 00000000 00001001
//以%d打印为9
printf("n的值为: %d\n",n);
//00000000 00000000 00000000 00001001 *pFloat得到的是这个,以%f的形式打印
//0 00000000 00000000000000000001001
//S = 0
//E = 0(E为全0,是一个无限接近于0的数)
//M = 1.000..
//(-1)^S * M * 2^E
//(-1)^0 * 1.000 * 2^(-127)
//打印为0.000000
printf("*pFloat的值为: %f\n",*pFloat);
//9.0放在float类型中
//9.0转化为二进制浮点数为
//1001.0
//转为科学计数法
//1.001*2^3
//(-1)^S * M * 2^E
//S = 0
//E = 3+127 = 130 二进制为--->10000010
//M = 00100000000000000000000
//0 10000010 00100000000000000000000 IEE的存储E规则
//01000001 00010000 00000000 00000000 在内存中的存储
*pFloat = 9.0;
//01000001 00010000 00000000 00000000
//以%d打印是一个非常大的正数
printf("n 的值为: %d\n",n);
//以%f打印将
//01000001 00010000 00000000 00000000用IEEE的转化规则转为
//0 10000010 00100000000000000000000
//S = 0
//E = 10000010 ---> 130-127 = 3
//M = 00100000000000000000000
//(-1)^S * M * 2^E
//(-1)^0 * 1.001 * 2^3 = 9.0
printf("*pFloat的值为: %f\n",*pFloat);
return 0;
}
运行结果
五、总结:
本章详细讲解了整型家族和浮点型家族数据类型在内存中的存储方式,制作不易,希望对各位有帮助。