当我使用标准 C 库中的 getenv()
函数时,我的程序从其父级继承了环境变量。
例子:
$ export FOO=42
$ <<< 'int main() {printf("%s\n", getenv("FOO"));}' gcc -w -xc - && ./a.exe
42
在 libc 中,
environ
变量被声明为 environ.c
。我希望它在执行时为空,但我得到 42
。更进一步的
getenv
可以简化如下:char * getenv (const char *name)
{
size_t len = strlen (name);
char **ep;
uint16_t name_start;
name_start = *(const uint16_t *) name;
len -= 2;
name += 2;
for (ep = __environ; *ep != NULL; ++ep)
{
uint16_t ep_start = *(uint16_t *) *ep;
if (name_start == ep_start && !strncmp (*ep + 2, name, len)
&& (*ep)[len + 2] == '=')
return &(*ep)[len + 3];
}
return NULL;
}
libc_hidden_def (getenv)
这里我只获取
__environ
变量的内容。但是我从来没有初始化它。所以我很困惑,因为
environ
应该是 NULL
除非我的主函数不是我程序的真正入口点。也许 gcc
通过添加作为标准 C 库一部分的 _init
函数来提醒我。environ
在哪里初始化? 最佳答案
这里没有什么神秘之处。
首先,shell fork 。 Forked 进程显然具有相同的环境。然后在子进程中执行一个新程序。有问题的系统调用是 execve
,它接受一个指向环境的指针。
因此,在执行二进制文件后设置的环境完全取决于执行 exec 的代码。
所有这些都可以通过运行 strace 轻松看到。
编辑: 因为问题被编辑为询问 environ
:
当您执行动态链接的二进制文件时,第一个执行任何操作的用户空间代码来自加载器。加载程序除其他外设置变量,如 argc
、 argv
或 environ
,然后才从二进制文件中调用 main()
。
再一次,所有这些的来源都是免费的。虽然 glibc 的源代码由于格式恶劣而难以阅读,但 BSD 的源代码很容易并且在概念上足够等效。
http://code.metager.de/source/xref/freebsd/libexec/rtld-elf/rtld.c#389
关于c - 程序如何继承环境变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31034993/