探索堆栈布局的代码:
#include <inttypes.h>
#include <stdio.h>
// POSIX 2008 declares environ in <unistd.h> (Mac OS X doesn't)
extern char **environ;
static void dump_list(const char *tag, char **list)
{
char **ptr = list;
while (*ptr)
{
printf("%s[%d] 0x%.16" PRIXPTR ": %s\n",
tag, (ptr - list), (uintptr_t)*ptr, *ptr);
ptr++;
}
printf("%s[%d] 0x%.16" PRIXPTR "\n",
tag, (ptr - list), (uintptr_t)*ptr);
}
int main(int argc, char **argv, char **envp)
{
printf("%d\n", argc);
printf("argv 0x%.16" PRIXPTR "\n", (uintptr_t)argv);
printf("argv[argc+1] 0x%.16" PRIXPTR "\n", (uintptr_t)(argv+argc+1));
printf("envp 0x%.16" PRIXPTR "\n", (uintptr_t)envp);
printf("environ 0x%.16" PRIXPTR "\n", (uintptr_t)environ);
dump_list("argv", argv);
dump_list("envp", envp);
return(0);
}
将程序编译为x
,我在经过消毒的环境中运行它:
$ env -i HOME=$HOME PATH=$HOME/bin:/bin:/usr/bin LANG=$LANG TERM=$TERM ./x a bb ccc
4
argv 0x00007FFF62074EC0
argv[argc+1] 0x00007FFF62074EE8
envp 0x00007FFF62074EE8
environ 0x00007FFF62074EE8
argv[0] 0x00007FFF62074F38: ./x
argv[1] 0x00007FFF62074F3C: a
argv[2] 0x00007FFF62074F3E: bb
argv[3] 0x00007FFF62074F41: ccc
argv[4] 0x0000000000000000
envp[0] 0x00007FFF62074F45: HOME=/Users/jleffler
envp[1] 0x00007FFF62074F5A: PATH=/Users/jleffler/bin:/bin:/usr/bin
envp[2] 0x00007FFF62074F81: LANG=en_US.UTF-8
envp[3] 0x00007FFF62074F92: TERM=xterm-color
envp[4] 0x0000000000000000
$
如果你仔细研究,你会发现argv
to 的参数main()
是一系列指向堆栈更上层字符串的指针的开始;(在 POSIX 机器上envp
可选的第三个参数main()
)与全局变量environ
和相同argv[argc+1]
,并且也是一系列指向堆栈上方字符串的指针的开始;argv
和指针指向的字符串envp
跟随两个数组。
这是 Mac OS X 上的布局(如果重要,则为 10.7.5,它可能不重要),但我可以肯定你会在其他类 Unix 系统上找到相同的布局。