C语言数据的存储读取

  • Post author:
  • Post category:其他


在C语言中,有一些基本类型,如int,float,double,char等,它们还分为有符号类型和无符号类型(unsigned int就是无符号整型),它们所能存储的数据范围不同。当然它们的存储方式也有所差异,接下来我们来了解一下它们的存储方式。

以下所讲都是以VS2022,X86环境下为例。

首先数据都分为有符号和无符号两种类型,以int类型为例,分为int(有符号),umsigned int(无符号),一个int类型的数据占用4个字节的空间,也就是32个bit。当一个变量被定义为有符号类型的数,那么规定其最高位是符号位,0代表正数,1代表负数。

计算机中的整数有三种2进制表示方法,即原码、反码和补码。

原码:直接将数值按照正负数的形式翻译成二进制就可以得到原码

反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码:反码+1就得到补码。

整数的原码反码补码都相同

int a= 1;a在内存中存储形式为:00000000 00000000 00000000 00000001

负数在内存中的是以补码的形式存储的

int a =-1;a在内存中的存储形式为:11111111 11111111 11111111 11111111

过程就是先得到原码:10000000 00000000 00000000 00000001

反码:11111111 11111111 11111111 11111110

补码:11111111 11111111 11111111 11111111.

在使用无符号类型的数据是需要小心思考,否则可能会出现问题

#include <stdio.h>
int main()
{
	unsigned int a = 9;
	for (a; a >= 0; a--)
	{
		printf("hwllow\n");
	}
	return 0;
}

这段代码看起来没有问题,但实际上是一个死循环。

首先a是一个无符号得整形,他的最小值就是0,他不会比0小,所以循环条件始终成立。

大小端

在不同的平台下数据在内存中的存储形式有差别。分为大端存储模式和小端存储模式

大端存储模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址

中。

小端存储模式:是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地

址中。

我们也可以通过一个程序来判断当前平台下是哪种。

int main()
{
	int a = 1;
	int* pa = &a;
	printf("%d", *(char*)pa);
	return 0;
}

当打印出来的数是1是就是小端存储,当打印出来的是0那就是大端存储。

首先a在内存中是00 00 00 01;

取出a得地址放入pa中,实际是a得首地址,再用char*强制类型转换就能只答应a首地址得数。

练习

#include <stdio.h>
int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d\nb=%d\nc=%d\n", a, b, c);
	return 0;
}

相信第一第二个答案并没有问题,那么第三个是怎么得到的,我们来分析一下。

首先得到-1得补码存入c中就是11111111.

%d是有符号整型得打印形式,那么c就要发生整型提升,也就是将c转换为int类型,那么新增加的空间就要补充数据。因为c是无符号类型,所以补0,但c是有符号数时就用符号位去补

那么c就是00000000 00000000 00000000 11111111.c得最高位是0,被认为是正数,就得到了255。

#include <stdio.h>
int main()
{
	char a = -128;
	printf("%u\n", a);
	return 0;
}

再C语言中规定有符号的char类型1000 0000代表-128.

所以a中存放的是1000 0000.

%u是打印无符号整形得数据。

所以a要整型提升,a是有符号的数,符号位是1.

所以a就变成:111111111 111111111 111111111 10000000

打印时%u认为a是无符号数,所以会打印一个很大的数。

#include <stdio.h>
int main()
{
	char a = 128;
	printf("%u\n", a);
	return 0;
}

这道题和上面的差不多,先将128得二进制写出来是1000 0000,128是正数所以直接存入a中,然后以%u的形式打印出来,还是整型提升,是有符号数,并且最高位是1,所以其他位置上补1

得到11111111 11111111 11111111 10000000.和上一题的答案一样。

你可能会疑惑,char能存的最大数是127,怎么能存进128呢?虽然规定了最大数是127,但当我们要强制存放时,也能存放进去,只是存进去后它代表的数就不是128了,从char的角度来看,存进来的是1000 0000,因该是-128。

所以虽然我们存进去了,但并没有正确的存入。代表的意义已经不一样。

#include <stdio.h>
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%d\n", i + j);
	return 0;
}

第一步都是先将数字转换为二进制

i:100000000 00000000 00000000 00010100

i补码:11111111 11111111 11111111 11101100

j:000000000 00000000 00000000 00001010

相加就是将它们两个的补码相加:11111111 11111111 11111111 11110110

%d打印有符号数,相加后得到的补码和-10的补码一样所以答案就是-10

浮点型数据存储

一个float类型的数可以表示为(-1)^s*M*2^E

即5.5换成二进制是101.1可以写成(-1)^0*1.011*2^2

M是大于等于1小于2的。所以当存入内存时,M的1就不存入内存只存入011。读取时在将1加上。

double和float差不多,如上图所示。

E是一个无符号数,但实际情况中也有可能出现是负数的情况,所以规定E在存入内存时,需要加一个中间数,这个中间数是E内存所能存储的最大数的一半,当E是内存是8bit是中间数就是127,是11bit就是1023。

当E全为零或全为一时, 就代表这个数是无限接近于零,或接近无穷大。

当E为0此时M就不加1,而是直接还原为0.xxxxxx的小数,代表无限接近0。

当E全为1,这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。



版权声明:本文为m0_74506452原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。