在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
转自:https://blog.csdn.net/weixin_33724659/article/details/88028054 为了说明这个问题,咱们简单的来说一下C里面变量在内存里面的存储: 1.栈区(stack)— 由编译器自动分配释放 ,存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。 2.堆区(heap) — 一般由程序员分配释放, 用来存储数组,结构体,对象等。若程序员不释放,程序结束时可能由OS回收。 3.全局区(静态区)(static)— 存放全局变量、静态数据、常量。程序结束后由系统释放。 4.文字常量区 — 常量字符串就是放在这里的。 程序结束后由系统释放。 5.程序代码区 — 存放函数体(类成员函数和全局函数)的二进制代码。
栈内存是有大小限制的,比如默认情况下,Linux平台的是8MB,如果超过这个限制,就会出现 stackoverflow,而堆内存并无限制,内存有多大就可以申请多大。 看完上面的说明,我们可以得出一个结论: 全局变量存放在全局区,在程序一开始就分配好了,而且局部变量在存放在栈区,运行的时候分配内存,用完之后内存会被自动释放。 但是这好像并没有说明变量名在哪里吧?比如下面这段C代码,a, b到底存在哪里?: 1 #include <stdio.h> 2 3 int a = 1; //全局初始化区 4 5 int main(int argc, char const *argv[]) 6 { 7 int b; //栈 8 b = a + 5; 9 printf("%d\n", b); 10 return 0; 11 } 为了搞明白这个问题,我们需要了解一下C语言的执行过程,C语言执行需要经过预处理(Preprocessing)、编译(Compilation)、汇编(Assemble)、链接(Linking)等几个阶段,在编译成汇编语言这个阶段就已经没有变量名了,使用gdb可以查看编译后的汇编代码: (gdb) disass main Dump of assembler code for function main: 0x0000000000400526 <+0>: push %rbp 0x0000000000400527 <+1>: mov %rsp,%rbp 0x000000000040052a <+4>: sub $0x20,%rsp 0x000000000040052e <+8>: mov %edi,-0x14(%rbp) 0x0000000000400531 <+11>: mov %rsi,-0x20(%rbp) 0x0000000000400535 <+15>: mov 0x200afd(%rip),%eax # 0x601038 <a> 0x000000000040053b <+21>: add $0x5,%eax 0x000000000040053e <+24>: mov %eax,-0x4(%rbp) 0x0000000000400541 <+27>: mov -0x4(%rbp),%eax 0x0000000000400544 <+30>: mov %eax,%esi 0x0000000000400546 <+32>: mov $0x4005e4,%edi 0x000000000040054b <+37>: mov $0x0,%eax 0x0000000000400550 <+42>: callq 0x400400 <printf@plt> => 0x0000000000400555 <+47>: mov $0x0,%eax 0x000000000040055a <+52>: leaveq 0x000000000040055b <+53>: retq End of assembler dump. 虽然上面这个很难读懂,但是应该能看到在这一大堆汇编指令执行的背后,并没有变量名这个东西,所有的变量名到最后都变成了内存地址,汇编指令操作的是各种寄存器和内存地址。
以上的内容有参考网上很多文章,仅供参考!有一点需要明白在操作系统里面,程序的内存地址并不是物理地址,而且通过一个基址+偏移量的方式的计算得到的虚拟地址,操作系统为了更好的管理应用在内存这个层面做了很多抽象。
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论