深入探讨数据在内存中的存储(上)

简介: 深入探讨数据在内存中的存储

一.整型在内存中的存储


①基本的数据类型:


1669213133923.jpg


我们都知道C语言有这么几种数据类型,那么在C语言为什么要分成这几种类型,类型区分的意义在哪里呢?


据笔者理解,类型的划分对于计算机来说它有两种含义:


①它肯定限定了这个类型开辟了多大的空间,限定了它的使用范围。


②它告诉计算机看待这个数据的视角。


1.1整形的原反补


我们都知道计算机中的整数有三种2进制表示方法,即原码、反码和补码。


原码:直接将数值按照正负数的形式翻译成二进制就可以得到原码。(正整数不需取反加1得补码,原码即补码)


反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。


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


看到这里,有xd可能要问,为什么负数要进行这么一番操作,直接像正整数一样取原码进行加减不方便吗?


1669213168453.jpg

1669213160071.jpg


我们简单举个例子,以int类型为例,如果仅原码进行计算,我们可以得出9+(-10)这个答案是-19,这显然是错误的。而按照补码进行计算,


1669213177326.jpg


显然利用补码可以得到正确的答案。那么从这可以先得出一点,即对于整形来说:数据存放内存中其实存放的是补码。还有一个点笔者补充一下:CPU只有加法器,那么统一为补码也方便计算。那么这么牛批的方法是怎么发明的,笔者也不清楚,只能说先辈真的厉害,吃水不忘挖井人,致敬先辈!!!


1.2整型的大小端存储


知道了整型在内存中是以补码的方式存储的,那么整型是否按照我们所设想的比如int a =20 ;16进制为:0x00000014 这样存储的呢?(在监视里内存是以16进制展现如何存储的)


1669213201160.jpg

1669213210045.jpg


通过vs的调试,我们可以发现它与我们设想的不一致,顺序并非如此,而是相反的,这又是为什么呢?我们就不得不说到大小端存储的概念了。


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


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


其实大小端本身没有优劣之分,只是依据不同的硬件,机器的存储模式会有所不同而已。比如说我们常用的 X86 结构是小端模式,而 KEIL C51 则 为大端模式。很多的ARM,DSP都为小端模式。这和机器有关。


掌握这个可以让我们对计算机的底层逻辑了解的更清楚。下面介绍一道百度笔试题。


题目:请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。


我们如何判断当前机器是如何存储的呢?以一个数比如说1,我们首先看一下这个数的存储形式。


0x00000001   根据大小端的概念,我们如果只取这个整形的最后两字节,来判断是1还是0就可以判断当前机器是大端还是小端存储。清楚了这件事就好办了。当然,我们这里可以强制类型转换和利用共用体两种方式来判断。

笔者会用两种方式实现这道题目:


强制类型转换:

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


共用体:

int check_sys()
{
 union
 {
 int i;
 char c;
 }un;
 un.i = 1;
 return un.c;
}
int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0;
}

1669213238418.jpg


可以看到笔者当前的机器是小端存储的。


1.3无符号型和有符号型


无论是考试还是面试,笔试,我们总会碰到一些类型转换的题目,这些题目本质上还是和计算机的存储挂钩的。下面笔者就通过几个题目和大家简要阐述一下这方面的一些坑。


各位可以自己看答案之前,想一下自己认为答案是什么,然后看一下答案,说不定会让你大吃一惊呢!


1669213256534.jpg

1669213264171.jpg

这段代码可能有不少朋友会觉得c应该是-1.那么在这里首先可以说明一下,无符号型数是没有负数的,因为它没有符号位。所以对于char类型来说,它的范围就是0-255.而-1的补码是11111111,所以值为255。(对了,这里还涉及到了整型提升,不过对于无符号型的char来说,还是高位补0,所以值还是为255)


1669213274406.jpg



相信这个代码得结果会令不少朋友大吃一惊,但是如果考虑到整型提升和打印类型的话,那么就可以分析得到个数。



1669213283574.jpg


这个数也是同样的.



1669213293754.jpg


这个结果是什么呢?可能通过基本的推断读者都可以猜测不可能简单的到i=0会停下来,因为unsigned int 类型的值是大于等于0的,所以我们进一步分析。当i=0然后再-1的情形。

1669213303837.jpg

1669213310485.jpg

结果也如我们所推断那样。这里我用了一个Sleep睡眠函数,让它再打印后会停止1000毫秒,方便我们观察,它的头文件是#include<windows.h>.


1669213320267.jpg

 这个函数会呈现怎样的结果呢?首先读者可能会纳闷,为什么会有strlen这个函数来计算整型数组,strlen不是计算字符串的长度吗?本质上strlen是碰到'\0'停止,而'\0'的ASCII值为0,所以说我们只要判断在什么时候a数组指向的值为0即可。

1669213354984.jpg

相关文章
|
20天前
|
消息中间件 存储 缓存
kafka 的数据是放在磁盘上还是内存上,为什么速度会快?
Kafka的数据存储机制通过将数据同时写入磁盘和内存,确保高吞吐量与持久性。其日志文件按主题和分区组织,使用预写日志(WAL)保证数据持久性,并借助操作系统的页缓存加速读取。Kafka采用顺序I/O、零拷贝技术和批量处理优化性能,支持分区分段以实现并行处理。示例代码展示了如何使用KafkaProducer发送消息。
|
3月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
111 11
|
4月前
|
监控 算法 应用服务中间件
“四两拨千斤” —— 1.2MB 数据如何吃掉 10GB 内存
一个特殊请求引发服务器内存用量暴涨进而导致进程 OOM 的惨案。
118 14
|
4月前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
232 1
|
4月前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
3月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
635 1
|
2月前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
3月前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
3月前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
38 3
|
3月前
|
存储 缓存 监控
Elasticsearch集群JVM调优堆外内存
Elasticsearch集群JVM调优堆外内存
73 1

热门文章

最新文章