全局变量地址固定、谁都能改、活到最后;局部变量住在栈上、靠 ebp 偏移定位、函数一返回就消失——两类变量活法完全不同。
10.8 讲清了栈帧,这一节对比住在栈帧里的变量和住在数据段的变量。
一、两类变量,四个对比
住在哪儿:全局在数据段(地址固定);局部在栈上(靠 ebp 偏移定位)。
怎么写:全局是 movl $5, _total;局部是 movl $5, -4(%ebp)。
活多久:全局活到程序结束;局部函数一返回就没了。
谁能改:全局谁都能改;局部只有这个函数自己。
四条一比,就能看出为什么两类变量解决的问题完全不一样。
二、地址固定 vs 随栈浮动
全局变量的地址在编译时就定死了——每次运行、每次调用都一样。 局部变量的地址是【ebp 减几】——同一个变量,在不同时刻栈帧位置不同,绝对地址就不同。 所以两种变量的写法必须区分:一个直接写名字,一个必须带偏移。 这不是编译器随心所欲,是被它们的【住址性质】逼出来的。
三、为什么局部变量不危险,全局变量危险
局部变量只有一个函数能碰——小范围、短生命,出了问题范围也小。 全局变量谁都能写、一直活着——改了它,你根本不知道是谁改的、什么时候改的。 所以有那条经验:能用局部就用局部,全局变量越少越好。 这句话背后不是风格问题,是寻址方式带来的现实后果。
四、那句老话的出处
【不要把局部变量的地址传出去】——这句话在汇编这一层有了硬解释。 局部变量住的那个格子,是【函数进出时临时立起来的一间屋子】。 函数一返回,栈帧拆掉,那间屋子就没了——传出去的地址就变成悬空的。 再用它,读到的就是别人的数据,或者直接崩掉——这类问题在高级语言里极难查,在汇编里一眼就看明白。
五、动手 Demo:全局变量和局部变量的工作原理
全局变量和局部变量,活法完全不同。 把两种变量的地址摆在一起对比,差别一目了然。
rows = [
("全局 _total", "movl $5, _total", "固定地址,每次运行都一样"),
("局部 a", "movl $5, -4(%ebp)", "ebp - 4,随栈帧浮动"),
("局部 b", "movl $6, -8(%ebp)", "ebp - 8,紧挨着 a"),
]
for name, how, addr in rows:
print(name, "|", how, "|", addr)
实跑输出:
--------------------------------------------------------------------
全局变量和局部变量的工作原理
--------------------------------------------------------------------
**全局变量和局部变量,活法完全不同。**
对比项 全局变量 局部变量
------------------------------------------------------------------
住在哪儿 数据段,**地址固定** 栈上,**靠 ebp 偏移定位**
怎么写 movl $5, _total movl $5, -4(%ebp)
活多久 整个程序运行期间 函数一返回就没了
谁能改 谁都能改(所以要小心) 只有这个函数自己
把两种变量的地址摆在一起,差别就一目了然:
变量 写法 地址是什么样的
---------------------------------------------------------------
全局 _total movl $5, _total 固定地址,每次运行都一样
局部 a movl $5, -4(%ebp) ebp - 4,随栈帧浮动
局部 b movl $6, -8(%ebp) ebp - 8,紧挨着 a
三条推论:
**局部变量在栈上【上下浮动】,所以只能用相对偏移来指。**
**全局变量地址固定,所以谁都能直接写它——这也是它危险的地方。**
**函数一返回,栈帧就没了,局部变量自然也跟着消失。**
所以那句老话是有出处的:
**【不要把局部变量的地址传出去】——它住的那间屋子,**
**函数一返回就被拆了。**
实测对比:全局变量写死地址,局部变量是 ebp 减 4、减 8。 函数一返回栈帧就没了,局部变量自然跟着消失——所以不能把它的地址传出去。
30 秒实验
- 在纸上写出一个全局变量的地址和一个局部变量的地址,说明它们为什么写法不同。
- 想一想:删掉一个函数的返回语句之后,局部变量会怎样。
常见误区
- 以为全局变量【方便】所以更好。它的代价是随时可能被别人改掉。
- 以为局部变量的地址可以随便传出去。函数一返回那间屋子就被拆了。
自测三问(点开对答案)
1. 全局变量和局部变量的地址性质有什么不同? —— 全局变量地址固定,编译时就定死;局部变量以 ebp 为基准按偏移定位,随栈帧浮动。 2. 为什么全局变量更危险? —— 谁都能改、且一直活着,出了问题很难查出是谁、在什么时候改的。 3. 为什么不能把局部变量的地址传出去? —— 局部变量住在栈帧里,函数一返回栈帧就被拆掉,那个地址就悬空了。- ☐ 下一节(10.10 循环的工作原理)
相关笔记
- 被调用函数的工作原理 — 栈帧是怎么立起来的
- 加载时生成的栈和堆 — 栈和堆各自管什么
- 将数据存入栈中 — 栈的规矩
- 🔵 计算机基础 · 索引 — 硬件底层的入门课
- ⚙️ 程序是怎样跑起来的 · 索引