变量内存地址
引子
- 程序运行时,代码中对局部变量赋值,反汇编可知本质上是通过内存地址对某块具体的内存进行赋值,那么程序如何知道变量的内存地址?如下:
int a;
a = 10;
理解
- 这里说的变量的内存地址,实际上是指虚拟内存地址,也是程序员所能感知的,在程序运行中,变量的虚拟内存地址是固定的,然而物理内存地址是随机的,内存使用时,虚拟内存地址映射到物理内存页,该行为的目标是不固定的,哪块空闲即可能映射到哪块,这也是虚拟内存的好处之一。
- 保存在data,rodata等分区的变量,内存地址在编译期就能确定,通过变量名的访问可以由在编译期将变量名映射为变量的内存地址来实现;但是局部变量和指针变量不同,其内存地址是不断变化的,每次执行都不同。
- 事实上所有的变量的地址都是在编译阶段确定下来了的,包括局部变量和指针变量本身,编译期局部变量的地址实质上是保存的一个相对栈顶的偏移量,访问也是通过该偏移量;指针变量本身其实也是局部变量或者其它区域的变量,只是保存的数据是内存地址,因此指针变量的地址在编译期也是可以确定的。
- 当变量的地址都是确定的,通过变量名的访问就可以通过在编译时将变量名访问替换为内存地址访问,因为变量名较多,编译器会生成一个符号表来管理变量名与地址的映射关系。
- 变量名编译完后就不存在了。
符号地址
引子
- 在C/C++等编译型语言中时常听到符号表,以及在python等脚本语言时常听到变量名实际上是符号地址,是什么意思?
- 变量名是否会占用内存?例如:在结构体声明中使用匿名结构体来增加变量名,代码如下:
struct A{
struct {
struct {
unsigned int enable;
} ftp;
struct {
unsigned int enable;
} http;
} upload;
};
struct B{
unsigned int fenable;
unsigned int henable;
};
- 经过在Linux下测试发现,结构体A和B内存占用是一样的,由此可得结论:变量名不会占用程序内存;那么多出来的变量名存储在何处?
理解
- 多出来的变量名存储在编译过程编译器的内存中,该结构就是符号表。
- 谭浩强老先生的《C程序设计》中关于变量名的描述:
“变量名实际上是一个符号地址,在对程序编译连接时由系统给每一个变量名分配一个内存地址。在程序中从变量中取值,实际上是通过变量名找到相应的内存地址,从其存储单元中读取数据。” - 个人理解:变量名就是编译期存在于编译器中的一个符号地址,编译或链接的时候,编译器或者链接器会给每个变量确定内存地址或偏移,并且通过符号表的方式将变量名和地址的映射关系保存起来,当代码中进行变量访问时,实际上是编译器通过变量名找到对应的内存地址,将变量名操作替换为内存地址操作,运行时程序访问该内存内存,从内存中读取数据。
- 因此变量名不会占用内存,编译后就不存在了,只是在编译时编译器需要占用内存地址来保存变量名与地址的映射关系。