1.locate.c的代码展示
2.运行结果
3.相关解释及知识点
1.locate.c的代码如下
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
static void show_pointer(void *p, char *descr) {
// printf("Pointer for %s at %p\n", descr, p);
printf("%s\t%p\t%lu\n", descr, p, (unsigned long) p);
}
char big_array[1L<<24]; /* 16 MB */
//char huge_array[1L<<31]; /* 2 GB */
char huge_array[1L<<30];/* 1 GB */
int global = 0;
int useless() { return 0; }
int main ()
{
void *p1, *p2, *p3, *p4;
int local = 0;
p1 = malloc(1L << 28);
p2 = malloc(1L << 8);
//p3 = malloc(1L << 32);
p3 = malloc(1L << 16);
p4 = malloc(1L << 8);
show_pointer((void *) big_array, "big array");
show_pointer((void *) huge_array, "huge array");
show_pointer((void *) &local, "local");
show_pointer((void *) &global, "global");
show_pointer((void *) p1, "p1");
show_pointer((void *) p2, "p2");
show_pointer((void *) p3, "p3");
show_pointer((void *) p4, "p4");
show_pointer((void *) useless, "useless");
show_pointer((void *) exit, "exit");
show_pointer((void *) malloc, "malloc");
return 0;
}
2.运行如下
zoe@zoe-virtual-machine:/mnt/hgfs/Notepad++$ gcc locate.c
zoe@zoe-virtual-machine:/mnt/hgfs/Notepad++$ ./a.out
big array 0x561043850040 94627852255296
huge array 0x561003850040 94626778513472
local 0x7fff383bbb84 140734136826756
global 0x561003850024 94626778513444
p1 0x7f6a4d528010 140094540513296
p2 0x56104680c260 94627902308960
p3 0x56104680c370 94627902309232
p4 0x56104681c380 94627902374784
useless 0x56100364f74d 94626776414029
exit 0x7f6a5d56c120 140094809227552
malloc 0x7f6a5d5c0070 140094809571440
3.详细解释及知识点
由运行结果和进程的虚拟地址空间的分布我们可以推出,三个全局变量big array,huge array和global由上至下位于读/写数据段(data段);主函数里的变量local以及p1到p4位于栈,但运行得到的地址实际上是是p1到p4的值,而不是p1到p4的地址,由于调用了malloc函数,它们所指的内容位于堆中;函数useless位于代码段(text段);库函数exit和malloc位于堆栈之间的共享库。(地址是从下往上增大的)
知识点
下图是示例可执行文件hello.c进程的虚拟地址空间
●程序代码和数据。对所有的进程来说,代码是从同一固定地址开始,紧接着的是和
(全局变量相对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初
始化的,在示例中就是可执行文件hello。
●堆。代码和数据区后紧随着的是运行时堆。代码和数据区在进程一开始运行时就被
指定了大小,与此不同,当调用像malloc和free这样的C标准库函数时,堆可
以在运行时动态地扩展和收缩。
●共享库。大约在地址空间的中间部分是一块用来存放像C标准库和数学库这样的共
享库的代码和数据的区域。
●栈。位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。和堆一
样,用户栈在程序执行期间可以动态地扩展和收缩。特别地,每次我们调用一个函
数时,栈就会增长;从一个函数返回时,栈就会收缩。
●内核虚拟内存。地址空间顶部的区域是为内核保留的。不允许应用程序读写这个区
域的内容或者直接调用内核代码定义的函数。相反,它们必须调用内核来执行这些
操作。