C/C++数据在内存中的存储方式

简介: C/C++数据在内存中的存储方式

C语言给定了一些基本的数据类型

char   类型
int    类型   
long   类型
float  类型
double 类型

前三者都属于整型家族,后两者属于浮点型家族,为什么char属于整型家族呢?这是因为字符是以对应的ASCII码值存放到内存中,本质上是属于整数的,所以将其归类为整型。

那么我们在创建这些变量且赋予它们具体数值的时候,它们又是如何将这些数值数据存放到内存中的呢?我们都知道任何形式的数据(字符,图片, 音频......)放到电脑中都是以二进制的形式存放的

例如 我们创建一个整型变量,并赋予它一个数值

int  a = 10;
a中的数据放在内存中需要转化为二进制形式
将10转化为二进制形式为 1010 因为int有32个比特位的大小,所以最终的形式如下
00000000000000000000000000001010

这样我们就解决了存放整数的问题,但很快会发现,如果存放一个负整数该怎么存呢?该怎么表示这个数字是负的呢?聪明的科学家想到了这样一个办法,那就是将这个二进制序列的最高位定义为符号位,如果最高位上的数字为0,那表示这个数字是正数,如果最高位上的数字为1,那表示这个数字是负数,例如下面的表示

int  a = 10;
a中的数据放在内存中转化为二进制形式为
00000000000000000000000000001010
int a = -10;
a中的数据放在内存中转化为二进制形式为
10000000000000000000000000001010

好了,现在正整数和负整数在内存中存放的形式都解决了,哈哈,不过问题又来了,正整数和负整数在进行加减运算的时候就出现问题了,如下

int a = 10;
int b = -1;
     a 在内存中的二进制形式为  00000000000000000000000000001010
假设 b 在内存中的二进制形式为  10000000000000000000000000000001
如果将a 与 b 相加 
a 00000000000000000000000000001010
+
b 10000000000000000000000000000001
= 10000000000000000000000000001011

a和b相加,结果却变成了 -11,怎们办,这里不得不佩服科学家的聪明,引入了原码 补码 反码的概念,那么这些具体有什么作用呢?接下来分析一下。

正数的原码 反码 补码相同
int a = 10;
a 的二进制形式为 
00000000000000000000000000001010  //原码
00000000000000000000000000001010  //反码
00000000000000000000000000001010  //补码
负数的反码为 原码的符号位不变,其他位取反。负数的补码为反码加1
int b = -10;
b 的二进制形式为
10000000000000000000000000001010  //原码
11111111111111111111111111110101  //反码
11111111111111111111111111110110  //补码

这里需要知道的是,无论正数还是负数,都是以补码的二进制序列放到内存中的

因此实际上,a放到内存中是补码  00000000000000000000000000001010

b放到内存中是补码  11111111111111111111111111110110,接下来我们通过编译器去验证一下。

验证结果是没有问题滴,说明确实是这样存储的,但至此,可能对其作用仍不了解,那接下来说一下反码 补码的具体的作用,还是以加法为例

int a = 10;
a 的二进制形式为 
00000000000000000000000000001010  //原码
00000000000000000000000000001010  //反码
00000000000000000000000000001010  //补码
int b = -5;
b 的二进制形式为
10000000000000000000000000000101  //原码
11111111111111111111111111111010  //反码
11111111111111111111111111111011  //补码
因为都是以补码存放到内存中,所以在内存中
a 为00000000000000000000000000001010
b 为11111111111111111111111111111011
a 00000000000000000000000000001010
+
b 11111111111111111111111111111011
= 00000000000000000000000000000101
转化为十进制就是5  是不是很奇妙,这就是反码 补码的妙用,非常漂亮的的解决掉正负数进行加减运算的问题,其他的乘除运算都可以转化为加法运算,这样也就同时解决掉其他的运算问题。
这里补充一点,补码取反加1是可以转化为原码的
我们试一试
11111111111111111111111111111011  这是b的补码,现在我们符号位不动,其他位取反
10000000000000000000000000000100  这是补码取反后的结果,接下来我们把它加1
10000000000000000000000000000101  这是加1后的结果,发生什么事了,是不是又变回了原码

接下来,举点栗子,加深对上面知识的理解

char a = -1;                   //注:char 是 signed char还是 unsigned char取决于编译器
signed char b = -1;                                         //不过一般都是signed char
unsigned char c = -1;
printf("%d %d %u", a, b, c);
那么打印的结果分别是什么呢?

一起分析一下吧

以上就是整型数字在内存中的存储方式,但仔细观察下图,会发现一个奇怪的现象



就拿int a 来说 我们分析的存储方式应该是00 00 00 0a  ,而编译器上却显示存储形式为0a 00 00 00

这其实就牵涉到大端,小端存储的问题,为什么会这样呢?因为int 类型接连占用四个字节,该空间的数据的存放位置就得有一个规定,我们同样可以将a中得数据以00 0a 00 00或者是00 00 0a 00的方式存储,但这些都太过麻烦了,00 00 00 0a 和 0a 00 00 00这两种存储方式最符合我们的思维习惯,就沿用至今,分别叫大端存储法和小端存储法。大端还是小端是取决于硬件的,与编译器无关,一般个人pc用的是小端存储法。

接下来我们一起分析一下大端与小端,然后再写个小程序来判断自己的设备采用的是大端还是小端

那我们怎么判断自己的设备是大端还是小端呢? 同样是 int a = 10; 我们想看看它是大端存放还是小端存放,只需查看该空间的第一个字节,因为空间的第一个字节是处于低地址的,如果该空间的第一个字节没有存放 0a 则说明是大端存放,如果存放了0a,则说明是小端存放。

代码实现如下

int main()
{
  int a = 10;
  char *p = (char*)&a;
  if (10 == *p)
  { 
       printf("小端\n");
  }
  else
  {
       printf("大端\n");
  }
  return 0;
}


目录
相关文章
|
3月前
|
存储
阿里云轻量应用服务器收费标准价格表:200Mbps带宽、CPU内存及存储配置详解
阿里云香港轻量应用服务器,200Mbps带宽,免备案,支持多IP及国际线路,月租25元起,年付享8.5折优惠,适用于网站、应用等多种场景。
942 0
|
5月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
129 2
|
3月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
142 26
|
3月前
|
存储 缓存 NoSQL
内存管理基础:数据结构的存储方式
数据结构在内存中的存储方式主要包括连续存储、链式存储、索引存储和散列存储。连续存储如数组,数据元素按顺序连续存放,访问速度快但扩展性差;链式存储如链表,通过指针连接分散的节点,便于插入删除但访问效率低;索引存储通过索引表提高查找效率,常用于数据库系统;散列存储如哈希表,通过哈希函数实现快速存取,但需处理冲突。不同场景下应根据访问模式、数据规模和操作频率选择合适的存储结构,甚至结合多种方式以达到最优性能。掌握这些存储机制是构建高效程序和理解高级数据结构的基础。
280 1
|
3月前
|
存储 弹性计算 固态存储
阿里云服务器配置费用整理,支持一万人CPU内存、公网带宽和存储IO性能全解析
要支撑1万人在线流量,需选择阿里云企业级ECS服务器,如通用型g系列、高主频型hf系列或通用算力型u1实例,配置如16核64G及以上,搭配高带宽与SSD/ESSD云盘,费用约数千元每月。
273 0
|
8月前
|
存储 程序员 编译器
玩转C++内存管理:从新手到高手的必备指南
C++中的内存管理是编写高效、可靠程序的关键所在。C++不仅继承了C语言的内存管理方式,还增加了面向对象的内存分配机制,使得内存管理既有灵活性,也更加复杂。学习内存管理不仅有助于提升程序效率,还有助于理解计算机的工作原理和资源分配策略。
|
6月前
|
存储 C++
UE5 C++:自定义Http节点获取Header数据
综上,通过为UE5创建一个自定义HTTP请求类并覆盖GetResult方法,就能成功地从HTTP响应的Header数据中提取信息。在项目中使用自定义类,不仅可以方便地访问响应头数据,也可随时使用这些信息。希望这种方法可以为你的开发过程带来便利和效益。
220 35
|
4月前
|
C语言 C++
c与c++的内存管理
再比如还有这样的分组: 这种分组是最正确的给出内存四个分区名字:栈区、堆区、全局区(俗话也叫静态变量区)、代码区(也叫代码段)(代码段又分很多种,比如常量区)当然也会看到别的定义如:两者都正确,记那个都选,我选择的是第一个。再比如还有这样的分组: 这种分组是最正确的答案分别是 C C C A A A A A D A B。
73 1
|
7月前
|
存储 Linux C语言
C++/C的内存管理
本文主要讲解C++/C中的程序区域划分与内存管理方式。首先介绍程序区域,包括栈(存储局部变量等,向下增长)、堆(动态内存分配,向上分配)、数据段(存储静态和全局变量)及代码段(存放可执行代码)。接着探讨C++内存管理,new/delete操作符相比C语言的malloc/free更强大,支持对象构造与析构。还深入解析了new/delete的实现原理、定位new表达式以及二者与malloc/free的区别。最后附上一句鸡汤激励大家行动缓解焦虑。