c 程序堆与栈,全局变量地址的研究.
先来一段简单的测试程序.
#include <stdio.h>
#include <stdlib.h>
int gi,gj,gk; //全局变量,先声明的变量地址要大一点.
int main()
{
int i=1;
int j=2;
int k=3;
char *p=(char *)malloc(10);
printf("global addr gi:%p,gj:%p, gk:%p\n",&gi,&gj,&gk);
printf("malloc p:%p\n",p);
printf("addr i:%p,j:%p, k:%p\n",&i,&j,&k);
return 0;
}
这是ubuntu gcc7.5.0 编译的.
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
Target: x86_64-linux-gnu
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
看一下运行结果
$ ./test_c
global addr gi:0x561d3b18b010,gj:0x561d3b18b014, gk:0x561d3b18b018
malloc p:0x561d3cc61260
addr i:0x7ffd48ecbeb4,j:0x7ffd48ecbeb8, k:0x7ffd48ecbebc
用gdb 调试来看, 又有另一番地址景象
global addr gi:0x555555755010,gj:0x555555755014, gk:0x555555755018
(gdb) next
malloc p:0x555555756260
(gdb) next
addr i:0x7fffffffdcd4,j:0x7fffffffdcd8, k:0x7fffffffdcdc
嗯, 看起来有点不爽. 是的,gdb调试和直接运行地址有些不同.
用gdb 调试看, 栈地址看顺眼了,应该从0x7fffffffffff 向下分配的.
但全局变量和堆地址它们的起始地址怎么还是看不透呢? 看起来像是从0x5555xxxxxxxx开始?
顺便看一下全局变量的地址, 用nm 查看
0000000000201010 D gi
0000000000201014 D gj
0000000000201018 D gk
看到gcc 编译地址与gdb调试地址是不一样的,有一个偏移, 与直接运行地址也不一样,有另一个偏移
加的偏移确实有点不伦不类,虽然我知道尽管运行是不会有问题的.
到centos7 下试一试吧. 看看是如何结果.
# gcc -v
gcc version 8.3.1 20190311 (Red Hat 8.3.1-3) (GCC)
./test_c
addr i:0x7ffc0a6a3d14,j:0x7ffc0a6a3d10, k:0x7ffc0a6a3d0c
global addr gi:0x60103c,gj:0x601040, gk:0x601044
malloc p:0x1477610
(gdb) next
addr i:0x7fffffffd8f4,j:0x7fffffffd8f0, k:0x7fffffffd8ec
(gdb) next
global addr gi:0x60103c,gj:0x601040, gk:0x601044
(gdb) next
malloc p:0x60a610
这个看着还比较顺眼. 栈从0x7fffffffffff 开始递减.
堆从0(0地址开始处已经被代码,数据占据)开始,向上递增.
查一下全局变量gcc 给的地址
000000000060103c D gi
0000000000601040 D gj
0000000000601044 D gk
gcc 编译地址, gdb调试地址及直接运行地址是一致的.
抛掉那个不爽快的ubuntu7.5 gcc 编译器. 我们还是可以得出结论.
堆是从低向高递长的, 起始点就是全局数据的结尾.
栈是从高向低递长的,其高点就是0x7fffffffffff.
建立这样的一个概念很重要!