C语言:数据的存储

1.数据的类型

在C语言中,基本数据类型有char、short、int、long、long long、float、double,那有没有字符串类型呢?答案是没有,哈哈哈。
在整型中,每个类型可分为有符号数和无符号数,即signed和unsigned,在vs2019中,默认的都是signed类型,所以想要表示无符号数时必须在前面加上unsigned。
除了这些类型,还有指针类型、空类型以及可以自己构造类型,如:struct、enum、union。

2.整型在内存中的存储

在了解整型在内存中的存储之前,我们先来了解一下什么时原码、反码和补码,这三种方法都可用来表示整数,由符号位和数值位组成,并且符号位的‘0’表示正数、‘1’表示负数。我们先看看负数的原反补码,
负数的原码:将该数转化成二进制形式,然后将最高位改为1;
负数的反码:在原码的基础上,符号位不变,其他位按位取反;
负数的补码:在反码的基础上+1;
而正数的原反补码就比较容易了,正数的原反补码完全一样。

对于整型来说,存在计算机中的是补码。我们来看一个例子:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
分别取a、b的地址,我们可以在内存中看到a存储的是0a 00 00 00,这是以十六进制存储的,0a正好是10,由于正数的原反补码相同,所以我们无法确认其存储的是哪一个,所以我们再看b,b在内存中存储的是f6 ff ff ff,将其转换成二进制形式,正好为-10的补码,由此可以证明整型在内存中是以补码进行存放的。
细心的同学会发现,一个int类型为四个字节,为什么a的存储方式是0a 00 00 00,而不是00 00 00 0a呢?这就涉及到了另外一个知识点,大小端。

3.大小端

什么是大小端呢?
大端存储:数据的高字节存储在低地址,低字节存储在高地址。
小端存储:数据的低字节存储在低地址,高字节存储在高地址。
有了大小端的概念,我们就知道VS2019中,整数是小端存储模式。我们拿一个十六进制数来举例,0x11223344,小端存储的话,在内存中的存储方式应该是44 33 22 11,我们在编译器上来验证一下:

int a = 0x11223344;

在这里插入图片描述
其存储方式确实是小端。
如果要我们设计一个程序来验证当前编译器是大端还是小端,我们改怎么办呢?只要我们取一下地址就可很好的来解决了,代码如下:

	int a = 1;
	char* p = (char*)&a;
	if (*p == 1)
		printf("小端\n");
	else
		printf("大端\n");

有同学可能会问了,这里为什么要将&a强转成char* 呢?如果我们直接取a的地址,会得到01 00 00 00,如果只取前面的01是不是很容易判断出来其值是否与1相等呢,所以这里强转成char*,再解引用就只会得到一个字节的内容,如果为1,就是小端,为0就是大端。

4.浮点型在内存中的存储

既然浮点型没和整型一起写,那他们的存储方式自然就不同了。
国际标准规定任意一个浮点数的表示形式如下:

  • (-1)^S * M * 2^E
  • (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
  • M表示有效数字,大于等于1,小于2。
  • 2^E表示指数位。
    所以我们在内存中存储的其实是S、M、E的值,拿5.5来举例,他应该表示成(-1)^0 * 1.011*2 ^2,也就是101.1,在小数点的左边,可以直接转换成二进制,小数点的右边则不一样,小数点右边的第一位为2的负一次方,右边第二位为2的负二次方,以此类推,我们会发现很多小数都不能精确的表达出来,如3.14。所以5.5在内存中对应的S、M、E的值分别为0、1011、2。
    对于32位的浮点数其存储方式如下:
    在这里插入图片描述

对于64位的浮点数其存储方式如下:
在这里插入图片描述
指数E的存储就比较复杂了,可以分为3种情况:

  1. 当E不全为0或不全为1时,其值等于本身+127。
  2. 当E为全0时,浮点数的指数E等于1-127(或者1-1023)即为真实值,
    有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于
    0的很小的数字。
  3. 当E为全1时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。

我们来看一个浮点数存储的例子:

int main()
{
	int n = 9;
	float* pFloat = (float*)&n;
	printf("n的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	*pFloat = 9.0;
	printf("num的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	return 0;
}

在这里插入图片描述
我们来看看为什么第一个*pFloat的值为0.000000,首先将n的地址强转为float *,9的表示形式为x00000009,其中s=0,E为全0,M=000 0000 0000 0000 0000 1001。所以浮点数可以写为(-1) ^ 0 × 0.00000000000000000001001×2^(-126),用十进制来打印就是0.000000;
再看num的值,9.0的表示形式为1001.0,(-1)^0 * 1.001 *2 ^2,那么内存中存储的应该是0、3 、和1001的值,写成二进制为s+E+M,其中s=0,E=3+127,M为有效数字001,要补全至23位,其表示如下:
0 10000010 001 0000 0000 0000 0000 0000,其打印出来就会是一个很大的数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值