栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言|数据的存储

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言|数据的存储

#1 类型的基本归类
整形家族分支备注
charunsigned charC语言标准没有规定char是指signed char还是unsigned char,这取决于编译器
signed char
shortunsigned short [int]C语言标准规定short是指signed short
signed short [int]
intunsigned intC语言标准规定int是指signed int
signed int
longunsigned long [int]
signed long [int]
浮点数家族
float
double
构造类型
数组类型
结构体类型struct
枚举类型enum
联合类型union
指针类型
int *pi;
char *pc;
float *pf;
void *pv;
空类型用途
void1. 函数的返回类型
2. 函数参数
3. 指针

#2 整数存储

定义在limits.h头文件中。
数据在内存中以2进制形式存储。
整数的二进制有3种表现形式:

  1. 原码
  2. 反码
  3. 补码

对于正整数来说,原码反码补码相同;
对于负整数来说,原码反码补码不同,需要计算才能得到:
原码:取绝对值后,将符号位的0变为1
反码:原码除符号位外,其他位取反
补码:反码+1
补码转化为原码和原码转化为补码的计算过程是相同的。
整数在内存中存储的是补码!

##2.1 大端、小端字节序

内存中的字节存储形式。
大端字节序:把数据的低位字节的内容存放在高地址处,高位字节的内容存放在低地址处。
小端字节序:把数据的低位字节的内容存放在低地址处,高位字节的内容存放在高地址处。
判断当前系统的字节序:

int judge(void)
{
	int num = 1;
	char* pa = (char*)# // 注意这里的强制类型转换
	//if(*pa == 1)
	//	return 1; // 返回1,表示小端字节序
	//else
	//	return 0; // 返回0,表示大端字节序
	return *p; // 由上面可得,返回的数与*p相同,因此可以直接返回*p
}

#2.2 例题

下列代码的运行结果为(以系统为32位为例):

int main()
{
	char a = -128;
	printf("%u", a);
	
	return 0;
}

a=-128,原码为1000 0000 0000 0000 0000 0000 1000 0000
反码为1111 1111 1111 1111 1111 1111 0111 1111
补码为1111 1111 1111 1111 1111 1111 1000 0000
因此a在内存中为1000 0000
因为a为signed char(一般编译器认为char为signed char),因此整型提升时,按符号位进行补位,结果为:
1111 1111 1111 1111 1111 1111 1000 0000
用%u打印时,最高位不看做符号位,而是数值,
因此为1111 1111 1111 1111 1111 1111 1000 0000 = 4294967168
如果用%d打印时,最高位为符号位,而且因为1111 1111 1111 1111 1111 1111 1000 0000为补码,要想知道其在有符号位时代表十进制的哪个数,需要先求出其原码,方法:除符号位外全部取反,再加1,最终得到
1000 0000 0000 0000 0000 0000 1000 0000=-128


下列代码的运行结果为(以系统为32位为例):

int main()
{
	char a = 128;
	printf("%un", a);

	return 0;
}

128=0000 0000 0000 0000 0000 0000 1000 0000
正数的原码反码补码相同,因此a为1000 0000。
因为a为signed char(一般编译器认为char为signed char),因此整型提升时,按符号位进行补位,结果为:
1111 1111 1111 1111 1111 1111 1000 0000
用%u打印时,最高位不看做符号位,而是数值,
因此为1111 1111 1111 1111 1111 1111 1000 0000 = 4294967168


下列代码的运行结果为(以系统为32位为例):

int main()
{
	char a[1000];
	int i;
	for(u = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
	return 0;
}

上面的代码随着循环的进行,a数组依次存入-1、-2、…、-127、-128、127、…、1后,存入0,接着存入1、…。数字0对应ASKII码为‘’,为字符串的结尾处,因此最终结果为255。

#3 浮点数的存储

定义在float.h头文件中。
一个例子:

int main()
{
	int n = 9;
	float* pFloat = (float*)&n;
	printf("n的值为:%dn", n);
	printf("*pFloat的值为:%fn", *pFloat);

	*pFloat = 9.0;
	printf("n的值为:%dn", n);
	printf("*pFloat的值为:%fn", *pFloat);
	// printf("*pFloat用%d打印为:%nn", *pFloat); // 这样写会报错
	printf("%d", 9.0);

	return 0;
}

结果为:
n的值为:9
*pFloat的值为:0.000000
n的值为:1091567616
*pFloat的值为:9.000000
0


任何一个二进制浮点数V可表示成下面形式:

  • (-1)s * M * 2E
  • (-1)s表示符号位,当s=0时,V为正数;当s=1时,V为负数
  • M表示有效数字,大于等于1,小于2
  • 2E 表示指数位

十进制浮点数5.5转化成二进制表示:101.1 —> 1.011 * 22 —>(-1)0 * 1.011 * 2E ;对应S=0,M=011,E=2
对于32位浮点数,最高位为符号位S,接着的8个位为指数E,剩下的23位为有效数字M

双精度浮点数的指数E有11位,有效数字M为52位。
E为无符号数,对于8位的E,取值范围为0 ~ 255;11位的E,取值范围为0 ~ 2047。但科学计数法中的E可以是负数,因此存入内存时E的真实值必须加上一个中间数。对于8位的E,中间数为127,11位的E,中间数为1023.例如,十进制的0.5,转化为二进制为0.1 —>1 * 2-1 ,此时的E为-1,在存入内存前,需要加上127,最终存入内存的数为126。
当E全为0时,有效数字M不再加上第一位的1,而是还原为0.xxxx。这样做是为了表示±0,以及接近0的很小的数。
当E全为1时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。

回到一开始的例题。9的二进制为0000 0000 0000 0000 0000 0000 0000 1001,按float的存储规则可得,0 00000000 00000000000000000001001,E=0-127=-127,是一个很小的数,约等于0。
9.0的二进制为1001.0—>1.001*23 ,按照float的存储规则可得,S=0,E=3+127=13=10000010,M=001(不足23位,在后面补0),存入存储中的二进制为0 10000010 00100000000000000000000,用%d打印时为1091567616。
注意:printf()函数打印时,会把float转换成double类型。
因此,printf(“%d”, 9.0);才会输出0,因为转成double后为64位,用%d输出,截取后面的32位,而后面的32个位都是0,所以才输出为0。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1026015.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号