数据在内存中的存储(学好编程必不可少!)

发布于:2024-03-14 ⋅ 阅读:(65) ⋅ 点赞:(0)

9efbcbc3d25747719da38c01b3fa9b4f.gif

 c语言中的小小白-CSDN博客c语言中的小小白关注算法,c++,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm=1001.2014.3001.5343

给大家分享一句我很喜欢我话:

知不足而奋进,望远山而前行!!!

铁铁们,成功的路上必然是孤独且艰难的,但是我们不可以放弃,远山就在前方,但我们能力仍然不足,所有我们更要奋进前行!!!

今天我们更新了数据在内存中的存储内容,

🎉 欢迎大家关注🔍点赞👍收藏⭐️留言📝

一、数据在内存中的存储

我们前面已经知道,数据在内存中是以二进制的形式存储的,二进制的表示形式又有:

原码、补码和反码,然后正整数的原反补码都相同,负数的各不相同。

原码:直接将数值按照正负数的形式翻译成二进制形式即可。

反码:将原码符号位不变,其他为按位取反。

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

在计算机中,对于整形数据来说:数据在内存中实际上存放的是补码。

为什么呢?

             因为在计算机系统中,数值统一用补码来表示和存储。原因在于,用补码来存储,可以将符号位和数值统一处理,同时加法减法也可以统一处理(CPU只有加法器),补码和原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

二、大小端自序和字节判断

2.1什么是大小端

我们知道一个整数在内存中以补码形式存储之后,我们还要考虑大小端。

我们先给出一个简单代码:

int main()
{
   int n=0x11223344;

   return 0;
}

我们调试一下会发现n的地址是这种形式,我们规定的是11223344(十六进制),为什么在内存中是倒着的呢,这就需要我们仔细地去思考一下了,这写其实就和大小端就关系了。下面我们来说一下什么是大小端,

其实整数在内存中是以二进制的形式存储,但是调试时为了方便显示,所以以十六进制显示,大家对这个不要有顾虑。

看一下这个图,这就是一张简单明了的介绍大小端的图,

所以大端字节序其实就是将一个数的低位字节存储到高地址处,高位字节序存储到低地址处

小端字节序就是将一个数的低位字节序存储到低地址处,高位字节存储到高地址处。

那么一个数哪里时低位字节哪里又是高位字节,其实就像0x11223344,44就是低位字节,11就是高位字节。

2.2为什么会有大小端?

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,一个字节为8 bit 位,但是在C语言中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看 具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤ 于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储和小端存储存 储模式。 例如:⼀个 16bit 的 short x ,在内存中的地址为 0x0010 x 的值为 0x1122 ,那么 0x11 为高字节, 0x22 为低字节。对于⼤端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。⼩端模式,刚好相反。我们常⽤的 X86 结构⼩端模式,而KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

然后我们现在考虑一下如何使用一个程序来判断当前机器是大端字节序还是小段字节序。

下面看一下这串代码:

#include <stdio.h>

int check_sys()
{
 int i = 1;
 return (*(char *)&i);
}

int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("⼩端\n");
 }
 else
 {
 printf("⼤端\n");
 }
 return 0;
}

这段代码便可以实现检测一个机器是大端还是小端了。

三、一些练习题

接下来我们再来看几个练习题吧,

3.1练习1

#include <stdio.h>
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;
}

大家看一下这串代码,你看一下应该会输出什么呢?

首先看一下第一个,char a,a是char类型的,

在看它之前,我们先来说一下signed和unsigned如何去理解。

signed char有符号的

unsigned char无符号的

我们知道,一个char类型占一个字节,就是8个bit位,

有符号其实就是其最高位是符号位,所以对于signed char,如果是整数,最大为01111111,也就是127,对于负数11111111也就是-128,所以有符号的取值范围为-128-127.

然后对于无符号的,最高位不代表着符号位,所以最大为11111111,也就是255.

说到这,我们应该就明白有符号和无符号的区别了。

然后在看-1的原码:10000000000000000000000000000001  补码11111111111111111111111111110  反码:1111111111111111111111111111

然后取八个就是11111111,然后转换成int类型呢,以符号位为标准,补1,所以就是11111111111111111111111111111111,这是反码,转化成原码,符号位不变,其他位按位取反再+1,然后就会发现等于-1,同样第二个也是这样,但是第三个不是,第三个是无符号,所以转化成整形时高位补0,就变成了00000000000000000000000011111111.然后最高位是0,0是整数,所以原码和补码相同,所以结果就是255了。

3.2练习2

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


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

下面我们再来看一下这道题,首先告诉大家,%u打印其实就是打印无符号的数

这里令char a = -128.这里用%u打印,原码:10000000000000000000000010000000.反码:11111111111111111111111101111111,补码:11111111111111111111111110000000,然后char类型最多存储8个比特位,所以就是10000000,但是%u打印时首先我们要整形提升,因为char是有符号类型的char,所以高位是符号位,所以就是11111111111111111111111110000000,就得到这样一个数,但是%u打印时我们又认为这是一个无符号数,所以最高位的1代表数,而不是符号位。而且不存在原码补码反码的差别,所以这就是原码,所以结果就是一个很大的数。

第二个也是一样,128原码是000000000000000000000000100000000,其他都一样,然后取八个存进char a中,就是10000000,然后要转换,因为char是有符号类型的,所以1还是代表着符号位,所以就是111111111111111111111110000000,然后%u打印时就代表了无符号类型,所以原码也是这个,因此这个题结果与上一个相同。

3.3练习3

#include <stdio.h>
int main()
{
 char a[1000];
 int i;
 for(i=0; i<1000; i++)
 {
 a[i] = -1-i;
 }
 printf("%d",strlen(a));
 return 0;
}

 看一下这个图片,这便是上面那串代码的题解了,这个题会打印255,因为strlen遇到‘/0’便会结束,然后char类型又是-127-128,然后当a[i]原码为0是便会结束。

 总结:

在本文中,我们深入探讨了负数在计算机内存中的存储方式,着重介绍了原码到补码的转换过程。通过分析原码、反码和补码的关系,我们揭示了补码在处理负数时的优势,并详细阐述了从补码到原码的推导过程。具体而言,我们总结了以下几点要点:

  1. 负数的表示:在计算机中,负数常用补码表示法。这种表示方法使得加法和减法运算都可以用同一种方式进行,简化了硬件电路的设计和运算规则。

  2. 原码到补码的转换:通过一系列的运算,我们可以将负数的原码转换为补码,这包括求原码的反码和对反码加1。这一过程可以通过逻辑运算和加法器实现。

  3. 补码到原码的还原:对于补码表示的负数,我们可以通过将补码的符号位以及其他位取反,并加1,得到其原码。这个过程在数字逻辑电路中有着清晰的实现方式。

  4. 内存中的存储:补码表示法在内存中的存储也是按照二进制位的方式进行的,但是需要特别注意符号位的处理。负数的补码和原码的差异是符号位的不同解释方式,即原码中符号位代表负数,而补码中符号位依然表示符号,但是其他位的含义与正数相反。

通过深入理解负数的存储方式,我们能够更好地理解计算机内存中数据的表示和处理,为程序员和计算机工程师提供了重要的基础知识。同时,这也有助于解释和理解在计算机系统中出现的一些奇特现象和错误。希望这篇文章能给你带来一些帮助。

本文含有隐藏内容,请 开通VIP 后查看