作者wei115 (NEET)
看板C_and_CPP
标题[问题] 区域变数是如何存在记忆体上的?
时间Sun Dec 8 16:50:35 2019
感觉C点比较弱,可能和ASM比较有关系,但这里人多,就发在这了:p
如题
小弟最近在写一个简单的C编译器,但对於区域变数是如何放在堆叠上的有些迷惑
例如
int main()
{
int a = 111;
if(a)
int b = 222;
int c = 333;
return 0;
}
一开始我是想说,编译器是在要使用时才把变数push到堆叠上的
像是遇到a = 111,就在堆叠上push一个111,然後只有if成立时才把222 push到堆叠上,
反之则跳过
可是看了好几个组合语言的范例(x86 Arm),好像会先计算在这函数中所有可能会用到变
数大小然後一次性push到堆叠上
例如刚刚的C程式,如果if成立会有a、b、c三个int,不成立会有a、c两个int
而看到的实作则是不管有没有b都先分配空间给他
但以C来说,在if内宣告的变数,他的生命周期应该就只在if内,但如果以这样的实作,
在if内的变数,只要知道他的记忆体位置,就算在if外也能存取(因为有事先分配空间,
而且没有回收),不太理解为什麽要这麽做
有没有相关资料是讲这方面细节的,谢谢
(写完後发现C点真的好少.....会不会被删阿orz....)
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 125.224.234.183 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1575795040.A.65E.html
1F:推 jerryh001: 因为快 一编译下去相对位置就固定了 而且scope只有在高 12/08 17:16
2F:→ jerryh001: 阶的时候才有意义 进到组合语言後没在管这个 12/08 17:16
3F:推 Fenikso: 你要怎麽只回收b, 移动rsp吗? 这样也没有真的回收喔 12/08 17:19
4F:推 harryooooooo: 照你说的在进到scope时才分配的话,就跟把scope当fu 12/08 17:20
5F:→ harryooooooo: nction call差不多意思了。语意上没什麽问题但是会 12/08 17:20
6F:→ harryooooooo: 有效能损失吧,只有看过把function inline的没看过 12/08 17:20
7F:→ harryooooooo: 反过来的。而且还要重新维护scope外的变数的offset 12/08 17:20
8F:→ harryooooooo: ,损失应该真的不小。 12/08 17:20
我自己猜想也是为了效能,但很好奇相关细节
因为直觉来想,如果是用到时再分配空间,那只需要读一次AST
如果是先分配,那就要读两次,一次确定空间,另一次产生组合语言
然後现在在想用哪种方式实作比较好,所以想知道来龙去脉
9F:→ Lipraxde: 如果 backend 是 stack architecture 的话就会看到你说 12/08 18:18
10F:→ Lipraxde: 的那种方式了,你看的范例应该都是 register architect 12/08 18:18
11F:→ Lipraxde: ure 12/08 18:18
我一开始以为register archure的stack也承担计算的功能,可是後来发现他只负责分配
空间和function call
12F:推 iaminanl: 如果-O都没有开,compiler就不会有优化(security conce 12/08 19:31
13F:→ iaminanl: rn是优化的一部分) 12/08 19:31
16F:推 iaminanl: 每个compiler都差不多,可以做多一点实验看看 12/08 19:35
我是用-O0测试的然後如果程式里没有call function,分配就比较随意(有变数再加一个偏
移)
如果有call,就会在function的开头先分配所有空间,然後不确定这是不是最佳化
※ 编辑: wei115 (125.224.234.183 台湾), 12/08/2019 19:56:47
17F:推 suhorng: 直接预先算好的优点前面推文说过了 另外 push/pop 会 12/09 09:06
18F:→ suhorng: 改变 stack pointer, 反而不一定有固定 %rsp + 位移快 12/09 09:07
19F:→ suhorng: 另外, 最後生命周期那段有错. 记忆体空间在那里并不代表 12/09 09:07
20F:→ suhorng: 变数还活着. 因为已经结束了生命周期, 再去存取是未定义 12/09 09:10
21F:→ suhorng: 的, 甚至同样的位址再分配给别的变数也有可能 12/09 09:11
嗯嗯,了解
我知道这是未定义行为,编译器随时可能最佳化掉这些行为
但对具体是依据怎样的标准去产生组合语言不太了解
我的理解是编译器後端一边遍历AST一边根据当下的语句去产生对应的组合语言
但遇到语句时要产生怎样的组合语言并不清楚
目前是看gcc产生的组合语言学习
但不知道为什麽要这样产生
23F:→ jepk007: if内变数的生命周期不也是整个函数吗 12/09 10:13
24F:→ xam: 自修吗? 这些东西计算机组织/结构,编译器的课程会学到.. 12/09 12:06
是自修没错
但目前看到的书没有很具体讲一个编译器要怎麽写
目前是边看资料,边读jserv的MazuCC的原始码学习
※ 编辑: wei115 (120.109.130.64 台湾), 12/09/2019 14:40:58
25F:推 nullptr: if内变数的生命周期只在if内喔, 出了之後再去读是syntax 12/24 03:57
26F:→ nullptr: error; 如果把&b存进pointer然後去读的话是UB 12/24 03:58
27F:→ nullptr: 因为是UB所以编译器可能拿B的空间给C用 12/24 04:00