剖析数据在内存中的存储(上)

简介: 剖析数据在内存中的存储(上)

数据类型的介绍

我们知道一些基本数据数据类型的使用,例如

类型的意义:

  1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
  2. 如何看待内存空间的视角

类型的基本归类:

整形:

浮点型:

还有一些构造类型、指针类型、空类型等。

整形在内存中的存储

我们知道过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。

那接下来我们谈谈数据在所开辟内存中到底是如何存储的`

int a=20;
int b=-10;

可以知道a和b都是整形分配了4个字节,那么他们是如何存储的呢?

原码、反码、补码

在此之前我们需要了解一下计算机中整数的三种二进制的表示方法。相信大家一定有所了解,在这里给大家简单介绍一下。

三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位

正数的原、反、补码都相同。

负整数的三种表示方法各不相同。

所以我们在此只说一下负数的情况

对于原码来说,正负数都是直接转化为二进制数即可得到该数的原码。

对于反码来说,原码的符号位不变,其他位取反即可得到。

对于补码来说,给反码+1即可得到补码。

对于整形来说:数据存放内存中其实存放的是补码。

为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统

一处理;

同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程

是相同的,不需要额外的硬件电路。

那么我们了解了之后看一下在内存中a和b的存储情况

int a=20;
//正数的原码补码相同
//00000000000000000000000000010100  在内存中存储是16进制我们将其转化为16进制
//0000  0000  0000  0000  0000  0000  0001  0100
//00 00 00 14  (16)

再看一下b的情况

int b=-10;
//原码 10000000000000000000000000001010
//反码 11111111111111111111111111110101
//补码 1111 1111 1111 1111 1111 1111 1111 0110
//十六进制ff ff ff f6

但这种情况似乎和存储的情况不太一样。

大小端介绍

什么大端小端:

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

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

为什么有大端和小端:

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元

都对应着一个字节,一个字节为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处理器还可以由硬件来选择是大端模式

还是小端模式。

我常用的编译器是vs,那么我们来验证一下,使用vs验是大端存储还是小端存储

#include<stdio.h>
int check_sys()
{
  int i = 1;//定义一个变量i=1
  return (*(char*)&i);//取出变量i的地址强制转化为(char*)类型 返回首字节的值
}
int main()
{
//1的16进制为00 00 00 01
//若小端存储则首字节为01即为1
  int ret = check_sys();
  if (ret == 1)
  {
    printf("小端存储");
  }
  else
  {
    printf("大端存储");
  }
  return 0;
}

练习

#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;
}

我们刚刚已经了解了整形的存储方式那么不妨来试一下这样一道题。

运行结果是 -1 -1 255

相信大家能知道为什么a和b是-1,那么接下来来分析一下为什么是255

unsigned char c=-1;
//原码    10000000000000000000000000000001
//反码    11111111111111111111111111111110
//补码    11111111111111111111111111111111
//因为unsigned char 仅一个字节所以截取8个bit位即为
//        11111111
//对于unsigned来说没有符号位则将111111111转化为10进制即为255

那么我们再来看另一道题

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

我们来逐步分析一下

char a=-128;
//原码  10000000000000000000000010000000
//对于char型只能取一个字节也就是10000000
//打印为整形对其作整形提升也就是
//      11111111111111111111111110000000
//%u 打印无符号的整数,也就是将补码11111111111111111111111110000000
//转化为10进制

结果是一样的,说明确实是这样进行存储的,如果大家不懂如何整型提升的话,向大家推荐一篇文章给大家详细了解整型提升:

http://t.csdn.cn/RfDIU 原作者:@bit_Sakura

那么我们来分析一下char——假设 是有符号的char

所以signed char的范围是-128~127

如果是无符号的unsigned char

所以unsigned char的范围是0·255

目录
相关文章
|
6天前
|
存储 C语言
数据在内存中的储存
数据在内存中的储存
11 3
|
6天前
|
存储 Java C++
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据,如局部变量和操作数;本地方法栈支持native方法;堆存放所有线程的对象实例,由垃圾回收管理;方法区(在Java 8后变为元空间)存储类信息和常量;运行时常量池是方法区一部分,保存符号引用和常量;直接内存非JVM规范定义,手动管理,通过Buffer类使用。Java 8后,永久代被元空间取代,G1成为默认GC。
18 2
|
9天前
|
存储
数据在内存中的存储(了解数据在内存中的存储规则,看这一篇就够了!)
数据在内存中的存储(了解数据在内存中的存储规则,看这一篇就够了!)
|
5天前
|
存储 C语言
【C语言进阶篇】整数在内存的存储——原码、反码、补码
【C语言进阶篇】整数在内存的存储——原码、反码、补码
|
9天前
|
存储 C语言
C语言----数据在内存中的存储(2)
C语言----数据在内存中的存储
14 0
|
9天前
|
存储 C语言
C语言----数据在内存中的存储(1)
C语言----数据在内存中的存储
|
14天前
|
消息中间件 存储 Kafka
实时计算 Flink版产品使用问题之 从Kafka读取数据,并与两个仅在任务启动时读取一次的维度表进行内连接(inner join)时,如果没有匹配到的数据会被直接丢弃还是会被存储在内存中
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
10天前
|
存储
数据在内存中的存储(2)
数据在内存中的存储(2)
24 5
|
10天前
|
存储 小程序 编译器
数据在内存中的存储(1)
数据在内存中的存储(1)
27 5
|
10天前
|
存储 安全 Java
SpringSecurity6从入门到实战之初始用户如何存储到内存
Spring Security 在 SpringBoot 应用中默认使用 `UserDetailsServiceAutoConfiguration` 类将用户信息存储到内存中。当classpath有`AuthenticationManager`、存在`ObjectPostProcessor`实例且无特定安全bean时,此配置生效。`inMemoryUserDetailsManager()`方法创建内存用户,通过`UserDetails`对象填充`InMemoryUserDetailsManager`的内部map。若要持久化到数据库,需自定义`UserDetailsService`接口实