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天前
|
存储 编译器 C语言
【C++】学习笔记——内存管理
【C++】学习笔记——内存管理
25 15
|
4天前
|
存储 C语言
数据在内存中的储存
数据在内存中的储存
11 3
|
2天前
|
C++
C/C++内存管理(2):`new`和`delete`的实现原理
C/C++内存管理(2):`new`和`delete`的实现原理
|
4天前
|
存储 Java C++
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据,如局部变量和操作数;本地方法栈支持native方法;堆存放所有线程的对象实例,由垃圾回收管理;方法区(在Java 8后变为元空间)存储类信息和常量;运行时常量池是方法区一部分,保存符号引用和常量;直接内存非JVM规范定义,手动管理,通过Buffer类使用。Java 8后,永久代被元空间取代,G1成为默认GC。
11 2
|
5天前
|
数据安全/隐私保护 C++
C++语言深入理解类的封装与数据隐藏
深入理解类的封装与数据隐藏
|
5天前
|
C++
C++函数的返回数据写法的思路
C++函数使用尾置返回类型、decltype、类型别名返回一个数组引用
|
2天前
|
程序员 编译器 C++
C++内存分区模型(代码区、全局区、栈区、堆区)
C++内存分区模型(代码区、全局区、栈区、堆区)
3 0
|
2天前
|
C++
C/C++内存管理(1):C/C++内存分布,C++内存管理方式
C/C++内存管理(1):C/C++内存分布,C++内存管理方式
|
2天前
|
存储 C语言 C++
【C++航海王:追寻罗杰的编程之路】C&C++内存管理你知道哪些?
【C++航海王:追寻罗杰的编程之路】C&C++内存管理你知道哪些?
6 0
|
3天前
|
存储 C语言
【C语言进阶篇】整数在内存的存储——原码、反码、补码
【C语言进阶篇】整数在内存的存储——原码、反码、补码