初识C语言·数据存储

这篇具有很好参考价值的文章主要介绍了初识C语言·数据存储。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 整数在内存中的存储

前面讲到,整数在计算机中的存储是以补码形式存储的,其中正数和负数也有些许差别,正数的三码相同,负数的就不相同了,那么这里就涉及原码反码补码。

原码:直接把整数用二进制的方式表达出来的就是原码。

反码:原码除了符号位不变,数值位按位取反就是反码。

补码:反码加1。

对于整型来说,计算机存储的一律是补码,这是因为使用补码可以把符号位和数值位一并处理了。

同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是 相同的,不需要额外的硬件电路。

相互转化我们可以这样理解,比如我们计算3-5,也就是3+(-5)

int main()
{
	//计算3 +  -5
	//3的原码00000000000000000000000000000011
	//-5的原码10000000000000000000000000000101
	//-5的反码11111111111111111111111111111010
	//-5的补码11111111111111111111111111111011
	//补码相加之后
	//补码11111111111111111111111111111110
	//反码11111111111111111111111111111101
	//原码10000000000000000000000000000010
//结果即是-2
	return 0;
}

所以补码和原码相互转化,cpu只需要一个加法器就可以解决完了,不需要额外的减法器之类的。

小tips:补码取反加1就可以直接得到原码,不用挨个挨个倒退回去。


2 大小端字节序和字节序判断

整数在计算机的存储我们现在是了解了,现在我们来看具体细节,均以VS2022为例进行操作。

int main()
{
	int a = 0x11223344;
	return 0;
}

初识C语言·数据存储,c语言,开发语言

定义一个整型,给它16进制的数字11223344,可能没接触过计算机的人就会认为存进去的时候就是按照从左往右的顺序进行存储的,但是实际上并非如此,由内存中我们可以看到存储是从右往左存储的,所以现在了解什么是大小端字节序(讨论超过一个字节的数据存储)。

大小端:

大端存储模式:是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存 在内存的低地址处。

小端存储模式:是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存 在内存的⾼地址处。

像a的11223344,其中11就是高位字节,44就是低位字节,从1到4也就是从高到低,在VS2022中11高位字节存储在高地址处,所以vs2022是小端机器。

那如果让你判断一下该机器是大小端机器的话?如何操作呢?

int main()
{
	int i = 0x1;
	char* pi = &i;
	if (1 == *pi)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

如上,我们只需要一个字节的内容,最开始的字节内容或者最后的字节内容就行,所以选择用char类型的指针来判断,如果解引用之后是高字节序的1在高地址处,那么就是小端存储,这是利用指针进行判断的,我们也可以使用联合体进行判断。

union Lab
{
	int a;
	char b;
}num;
int main()
{
	num.a = 1;
	if (1 == num.b)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
	return 0;
}

因为联合体里面的元素是共用空间的,所以我们创建一个整型,一个字符类型,使整型取1,接着就是判断第一个空间是不是1就行了。


3 整数存储练习题

代码1:

int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d,b=%d,c=%d", a, b, c);
	return 0;
}

问:代码的运行结果是什么?

在vs里面char ,signed  char类型是一样的所以两个的结果是一样的,因为-1的补码是32个1,截断8个bit位之后,就是11111111,进行整型提升,对符号位进行提升,最后也是32个1,所以a b的结果都是-1,那么,unsigned char类型的没有符号位,全是数值位,截断之后是11111111,提升之后是32个1,32个1也就是2^8 -  1,所以c是255。

代码2:

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

首先我们要知道char类型的数据(有符号的)的数值范围是-128——127,所以char a = 128是超出了数据范围的,那么a实际的值是-128(可以用%d验证一下),如果a是130,那么用%d打印出来就是-126,所以当数据范围超了之后的值其实就像一个轮盘一样,绕圈圈绕回来的。

既然a的数值是-128,占位符是%u,是无符号整型,所以会进行整型提升,因为-128比较特殊,它的二进制原码是1000 0000,所以整型提升之后,原码就是1111 1111 1111 1111 1111 1111 1000 0000,这就是原码,因为是无符号整型,所以三码是一样的,那么打印出来就是一个很庞大的数值,4294967168。
那么如果a是-128呢?因为截断之后的原码都是1000 0000,整型提升的结果也是一样的,所以最后的结果没有改变,都是4294967168。

代码3:

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

strlen,就是用来找0的,如果里面有个0,那么就停止了。数值的读入可以认为是一个循环,char类型的循环可以认为是-1 ……-128 127 126 ……0,可以认为是这样的一个循环,所以char a[1000]里面的数值也是这样的,那么从-1 到 0 一共有255个数,所以打印的结果就是255。

初识C语言·数据存储,c语言,开发语言

代码4:

unsigned char i = 0;// 0 -> 255
int main()
{
	for (i = 0; i <= 255; i++)
	{
		printf("Hello world\n");
	}
	return 0;
}

unsigned char的范围是0 - 255,那可能就容易以为循环次数是256次,就打印256个Hello world,但是实际上并非如此,如果要结束循环,那么i 的值就应该是256,但是i到256的时候,就变成了0,数值循环嘛,所以造成了死循环。

代码5:

int main()
{
	for (unsigned int i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}
	return 0;
}

有了代码4的理解,这段代码同理可得是一个死循环,因为unsigned int的值不可能为负数,所以循环会一直走下去。


4 浮点数在内存中的存储

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

初识C语言·数据存储,c语言,开发语言

让我们带着问题去解决这个知识点——为什么差别会那么大?

首先我们要知道浮点数在内存中怎么存储的。

根据国际标准IEEE(电气电子工程师学会)754,任意一个二进制浮点数V可以表示为下面的形式:

V = (-1)^S * M * 2^E

其中(-1)^S表示符号位,当S等于1是,V就是负数,S为0时,V就是为整数,这其实和整数存储的符号位是很像的,1是负数,0是整数。M表示有效数字,M是大于等于1,小于2的(有点类似于科学计数法),2^E表示指数位。

举个栗子,十进制的5.0,二进制表示就是101.0,相当于1.01 * 2 ^ 2,按照V的格式,可以得出S = 0,M= 1.01,E= 2,有点像科学计数法吧?指数位的2^2就像是科学计数法里面的10的几次方一样,这就是二进制的科学计数法。十进制的-5.0,S = 1,M = 1. 01,E= 2。

根据IEEE 754规定,对于32位的浮点数,最高位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M,

初识C语言·数据存储,c语言,开发语言

对于64位的浮点数·,最高位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M。

初识C语言·数据存储,c语言,开发语言

当然,存储并不是那么简单就完成了的,IEEE 754对于有效数字M和指数E还有一些特别的规定。

因为M>=1&&M<2,也就是说M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分,IEEE 754规定,在计算机中存储M的时候,默认这个数第一位总是1,因此可以被舍去,只保留小数部分,比如保留1.01的时候,只保留01,等到读取的时候在把第一位加上去,这样做的好处是可以节省1位有效数字,以32位浮点数为例,留给M只有23位,但是舍去1之后,等于可以保留24位有效数字

关于E,首先它是一个无符号整数,这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我 们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存⼊内存时E的真实值必须再加上 ⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。⽐如,2^10的E是 10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

那么中间数存在的意义是什么呢?像前面讲char取值一样,数值取值就是一个循环,加一个中间数就可以表示负数了。

浮点数取的过程还分为3种情况:
E不全为0或全为1,比如表达0.5在内存中的存储,因为0.5的二进制位表达是0.1,所以是1.0*2^(-1),E是126,0111 1110,整数部分是0,补齐就是24个0,所以二进制表示就是

0 0111 1110 0000 0000 0000 0000 0000 0000。

E全为0,这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字。

E全为1,这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s)

ok关于浮点数的存储就说到这里,我们来看题目

为什么9用浮点数指针接收的时候,打印出来的结果就是0.000000了,9的二进制序列是

0000 0000 0000 0000 0000 0000 0000 1001

那么把它按照浮点数形式拆分的话,符号位为0,指数为0000 0000,剩下的23为有效数字是000 0000 0000 0000 0000 1001,这是指数全为0的情况, 所以V = (-1)^0 *000 0000 0000 0000 00001001*2^(-126) = 1.001 * 2 ^ (-146),这是一个接近于0的数,所以用十进制小数表示就是0.000000。

那么为什么用整数打印浮点数9.0是1091567616,首先浮点数9.0二进制是1001.0,即是1.001*2^3,所以9.0 = (-1)^0 * (1001) * 2^3,S = 0,M = 00100000000000000000000,E = 130,即使10000010,最后表达出来就是0 10000010 00100000000000000000000,这是个32位的二进制的整数时,解析出来就是1091567616.

Tips : 不是所有的浮点数都可以表达出来的,君可自行实验。文章来源地址https://www.toymoban.com/news/detail-796710.html

到了这里,关于初识C语言·数据存储的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 初识Ceph --组件、存储类型、存储原理

    ceph Ceph(分布式存储系统)是一个开源的分布式存储系统,设计用于提供高性能、高可靠性和可扩展性的存储服务,可以避免单点故障,支持块存储、对象存储以及文件系统存储应用。使用C++语言开发。ceph能够通过网络将数据分散存储在多台独立设备上 ceph具有可扩展性:

    2024年02月05日
    浏览(36)
  • GO语言-区块链离线钱包开发之如何存储私钥

    # 如何存储私钥 在确保私钥安全的情况下,为了更好的体验,我们需要让钱包把私钥存储起来。给用户更好的体验感。Geth是将私钥通过加密技术转换为json格式的文件,这个文件虽然是明文的,但是解析它的时候需要密码,否则将无法解密。 在Geth中,使用`personal.newAccount(\\\"p

    2024年02月16日
    浏览(49)
  • C语言数据的存储

    提示: 本篇内容深度剖析数据在内存中的存储: C语言的内置类型 char 字符数据类型 1字节(8bit位) short 短整型 2字节(16bit位) int 整型 4字节(32bit位) long 长整型 4/8字节 long long 更长的整型 8字节 float 单精度浮点型 4字节 double 双精度浮点型 8字节 其实char类型也可以归到整型里面,因

    2023年04月22日
    浏览(34)
  • C语言:数据的存储

    C语言:初识C语言 C语言:分支语句和循环语句 C语言:函数 C语言:数组 C语言:操作符详解 C语言:指针详解 C语言:结构体 一转眼我们C语言系列的文章已经迎来了第八篇,虽然我鸽了很久了又。今天重新来写这篇,希望这个系列可以坚持下去。从第一篇该系列文章发布至今

    2024年02月11日
    浏览(31)
  • C语言数据存储 — 整型篇

    在C语言中,了解相关数据存储对一名优秀程序员来说是至关重要的! 通过相关原理,从而更加深入地理解计算机如何存储和操作数据,这对于编程人员来说是非常重要的。只有深入理解计算机存储和操作数据的原理,才能编写出更加高效、可靠的程序。 本文将详细介绍C语言

    2024年02月09日
    浏览(47)
  • 进阶C语言——数据的存储

    Hello,时间过的好快,从我一开始在csdn写的第一篇文章,距离现在已经过去一个多月了,我也在csdn收获了一些粉丝,你们的点赞就是我的动力,希望大家也越来越强,好了,进入我们的正题 ,初阶C语言也更完了,现在我们要开始我们的进阶C语言,在这里,小编带大家一起沉

    2024年02月16日
    浏览(79)
  • C语言数据存储 —— 浮点型篇

    浮点数在内存中的存储方式对程序员来说非常重要。理解浮点数的存储方式可以帮助程序员避免一些常见的错误,如:溢出和下溢、舍入误差和类型转换。此外,了解浮点数的存储方式还可以帮助程序员优化代码,提高程序的性能。因此,对一名优秀的程序员来说,理解浮点

    2024年02月13日
    浏览(37)
  • c-语言->数据在内存的存储

    文章目录 系列文章目录 前言 目的:学习整数在内存的储存,什么是大小端,浮点数的储存。 在讲解操作符的时候,我们就讲过了下⾯的内容: 整数的2进制表⽰⽅法有三种,即 原码、反码和补码。 正整数的原、反、补码都相同。 负整数的三种表⽰⽅法各不相同。 原码:直

    2024年02月04日
    浏览(31)
  • 华为云中对象存储服务软件开发工具包(OBS SDK) C语言介绍

          华为云的OBS介绍 :摘自华为云官网:https://support.huaweicloud.com/obs/index.html       华为云的对象存储服务(Object Storage Service, OBS)是一个基于对象的海量存储服务 ,为客户提供海量、安全、高可靠、低成本的数据存储能力。       OBS系统和 单个桶都没有总数据容量和对象

    2024年02月09日
    浏览(69)
  • 【C语言】数据在内存中存储练习

    废话不多说直接上题目: 写出-1这个数的二进制补码 当类型为char的时候数据需要截断储存 当数据以整数类型打印的时候就要发生整型提升、 如下分析: 当把-1的补码放到char 类型的数据中存储是会发生截断如图所示: 所以a,b,c,中存放的都是11111111 但是当以整数的形式取出来

    2024年02月06日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包