C/C++变量与内存

当你迷茫的时候,请点击 目录大纲 快速查看技术文章,相信你总能找到前行的方向

前情提要

上文 速学C/C++启蒙 我们讲了一个新版本的取经故事,里面暗含编程的基础知识,变量与内存,本文我们用硬核的技术来解读。

有多硬核呢?手搓内存的那种……

内存解密

内存像什么?

像我家的一亩三分地,我可以给它尽情划分,这块种西瓜,这块种黄瓜,那块种青菜,那块地种辣椒……

最像的是那种 LED 显示屏,很多 LED 点阵的那种,每个点就是一个 bit 位,最简单的就是那种只有亮与不亮的那种。

我们自己也可以 diy 出一个巨形LED内存条,每行只有8个灯(1Byte),当有1024行(1K)时,我们就有了1KB的内存,1024*8=8192 个 LED 小灯,也就是1KB=8192bit,这是要斥巨资搞啊!

如果我再重复搞10个1KB的内存块,就是10KB

同理,我如果来 1024个1KB 的内存块,就是1024KB=1MB

再来1024个1MB的内存块就是1GB,我们来算一笔账:

1GB=1024MB=1024*1024KB=1024*1024*1024B=1024*1024*1024*8bit = 需要 8589934592 个 LED 灯85 亿个 LED,看起来用 LED 做内存成本还是太高了哈!

现在哪个内存不是几十个G起步,所以内存贵的不是没有道理的,你要想到里面有几百亿个灯呢。

1KB 内存玩法

由于预算不足,我就弄个1KB的内存玩玩吧(算了,还是用画的吧),很多单片机最开始内存也是很小的,但也是可以玩的。

试试看存一些东西,看得出来我写了什么吗?

ILY = I Love You,你如果想表白一个程序员女生,可以试着给她发这样的一串暗语:

0x00A5
0x00A2
0x00BA

你说她会不会看懂你的意思呢?看不懂就直接明说吧,没啥大不了的

不要拿幸福作赌注,宁可出点错也千万不要错过!

模拟运行

就这样,我们1KB的LED内存条就算打造好了哈!还能做表白神器,而且这些灯既是小灯又是开关,一按下去它就亮起来了。我给每一行都编了个号码,从 0 开始到 1023 结束,用十六进制表示为:0x0000 ~ 0x03ff,总共 1024 行(Byte),8192 个灯(bit)。

没有 cpu,我们手搓不了,就拿自己当 cpu 吧,可以读取内存(采用瞪眼法)和操作内存手动按灯)。

好了,一台人形计算机就搞出来了,我真是个天才!天才第一步,先算1+2=?

简单吧,陈景润老师双手表示赞成,算了,我们挑战一下低级版的1+2吧,没错,就是小学生算的那个……

由于瞪眼法,易得1+2=3

说到瞪眼法,就不得不提拉马努金了,老师哈代问他,什么是瞪眼法啊?

“瞪眼法就是把眼睛睁开,瞪着问题看,等下答案就出来了……”

哦,这样啊?那我也试试,但我瞪出来的结果是眼药水,这位印度的瞪眼大神,简直是个行走的公式发明机,可惜英年早逝,再给他点时间说不定就能把 1+1 给瞪出来了

那我们用人形计算机算一下,类似笔算

10 号内存块(十六进制的地址为 0x000a = 十进制为 10)放置一个 1,怎么表示呢,有 8 个 led 灯,我可以亮 1 个灯表示 1,亮 8 个灯表示 8,也可以,但是最大只能表示 8 了

很浪费!正确的做法用二进制,0b00000001 表示 10b00000010 表示 20b11111111 表示 255,即:

#1 = 0x0001 = 0b00000001 = 2^0
#2 = 0x0002 = 0b00000010 = 2^1
#3 = 0x0003 = 0b00000011 = 2^1+2^0
……
#255 = 0x00ff = 0b11111111 = 2^7+2^6+2^5+2^4+2^3+2^2+2^1+2^0

哇,小小的 8 个灯,一下子可以表示 255 个数,是不是很神奇!比之前只能表示 8 提高了 32 倍之多!不得不佩服,人才!我们伏羲八卦图就含有二进制的思路,二进制也赋予了现代计算机的灵魂。

那我就手动编程,在10 号位置对着最后一个灯按了下去,那个灯就亮了,

也就是在 10 号位置(地址 0x000a)放一个 1(0b00000001),说人话就是 10 号位置有个 1,记为 a=1;

这个 a 就是个变量1 就是数值,这是给人看的助记,然而编译器编译后给机器看的就大概就是,地址:数值,如下所示:

0x000a : 0b00000001

那趁热再来一个,在 11 号位置(地址 0x000b)放一个 2(0b00000010),记为 b=2

0x000b : 0b00000010

之后就进入到 cpu 运算环节了,

  1. 用瞪眼法看到 10 号位的值,哦,是 1
  2. 用瞪眼法看到 11 号位的值,哦,是 2
  3. 用人形 cpu(脑子)计算 1+2,得到 3
  4. 把结果往 12 号位置放一下,记为 c = a + b,也就是 3,我赶紧手动编程,等下忘记了,

0x000c:0b00000011

整个用到的内存图就是这样了:

计算完毕,完美!

那如果再复杂一点,算一下平方吧,

(1+2)*(1+2)=?

前面步骤一样,计算左边的(1+2)得 3,二进制值为 0b00000011,存入 12 号位置 c,即 0x000c:0b00000011

再计算右边的(1+2)得 3,二进制值为 0b00000011,存入 13 号位置 d,即

0x000d:0b00000011

最后计算 c*d,也就是 3*3,我小学的 DNA 告诉我,三三得 9,用二进制表示为 0b00001001,再把 9 存到一个位置,就存到 14 号位置 e,即

0x000e:0b00001001

再来看看现在内存的全貌:

总共 1KB 的内存,我们在运行的时候用于存储阶段性的成果,也就是变量数值,用了 5B,厉害吧?

发现没有?内存就像是我们小时候的草稿纸,首先拆分计算的步骤,每计算一步就记录下来(写内存),计算下一步就看看上步的结果读内存),最后再计算得出结果(CPU 运算),那些变量就像是解方程设的未知数 x,y,果然,技术源于生活啊!

还是那句话,自己动手,丰衣足食 ,多动动手动动脑,以最原始的状态去设计(从无到有),多以计算机的角度去体验,你就更能明白和理解计算机,它为什么这样设计和运行。

在上面的人形计算机,我还简化了计算机取指令的步骤,只记录了变量,那些加减乘除的符号呢?计算机肯定也是要记录的,这就是代码方法区了,在 jvm 会存储到元空间内存,为什么又是内存?因为要与CPU打交道,如果存磁盘,那得慢成一坨翔了!

变量

变量在这起到什么作用呢? 我们上面说过了,助记符,对应内存地址,不过我觉得变量的重要作用是可以最大限度的复用内存

怎么说呢?其实在上面 (1+2)*(1+2)=? 我就偷偷地用了变量的复用,不知道你发现没有?来回顾一下:

我在计算左边的(1+2)用到了 10,11,12号内存,分别存在10号内存了1(a=1), 在11号内存存了2(b=2)

在12号内存存了3(c=a+b=1+2=3),可以解读为10号内存值11号内存值加和的结果存放到12号内存

左边这里都没有什么问题,内存都是必须要用的,用了3B,而且省不了一点点,那我再计算右边的(1+2)时候,我用了3B吗?没有,我用了1B,因为1,2这两个值在计算左边的时候已经存到了10,11 号内存,那计算右边的(1+2)我只需要把10,11 号内存的数值取出来加和运算得到3,存入到13号内存,即d=a+b=1+2=3

  1. 不复用变量的情况,即来一个数字就用占一块内存,那这个示例 (1+2)*(1+2)=? 有4个明确的数字 1,2,1,2,那我用 10, 11, 20, 21号内存分别存放,用伪代码来展示一下:
int a=1; // 10号内存放入1
int b=2; // 11号内存放入2
int c=a+b; // 12号内存放入计算结果3

int x=1; // 再来一块内存,假如是20号内存放入1
int y=2; // 再来一块内存,假如是21号内存放入2
int d=x+y; // 13号内存放入计算结果3

int e=c*d; // 14号内存放入计算结果9

这里我们简单理解每一个不同的变量对应着一块内存存放数据,那这里面我们用到了 a,b,c,x,y,d,e 7块内存,占我LED内存条7B(我设定每个数用1Byte=8bit存储)

  1. 复用变量 a=1,b=2后就变成了:
int a=1; // 10号内存放入1
int b=2; // 11号内存放入2
int c=a+b; // 12号内存放入计算结果3

// 复用变量a,b
int d=a+b; // 13号内存放入计算结果3

int e=c*d; // 14号内存放入计算结果9

用到了 a,b,c,d,e 5块内存,占我LED内存条5B,少了2B,不明显是吧,那我换成百分比皮一下,减少了28.6%呢?

还可以继续优化,左边和右边(1+2)结果不都是一样的吗?那我直接复用结果c

  1. 复用变量 c就变成了:
int a=1; // 10号内存放入1
int b=2; // 11号内存放入2
int c=a+b; // 12号内存放入计算结果3

// 复用变量c
int e=c*c; // 14号内存放入计算结果9

用到了 a,b,c,e 4块内存,占我LED内存条4B,比最开始的7B少了3B,换成百分比就减少了42.9%呢,厉不厉害,内存一下子减半了,哈哈!

虽然有点无语,这不就少个1B 2B的事情吗?但我这只是用个小示例模拟,而且一个数据占的可不是1B甚至会更大,而现实生产上有大量的方法计算,有大量的变量和内存占用,我们有的java项目没有1个G都启动不起来,那你估计一下有多少变量占据着内存?所以,变量的复用确实能起到非常明显的效果,可不要小瞧它哦!

总结

我们来稍微总结一下,列个表格来类比它们的关系

术语饰演者备注
CPU做加减乘除之类的运算,读写内存
内存草稿记录每一步计算结果
读取内存眼睛采用瞪眼法,查看内存里面的数据
写内存用手动按灯(手动编程),点亮对应位置的灯
变量未知数x,y用来代表某个地址,CPU会根据地址取出内存值,给人感觉就像是数值存到了变量里面

后面内容会越来越精彩,走过路过,千万不要错过,不求赞助,但求请点赞收藏加关注……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铅笔侠_龙虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值