它只是一个指向环境的指针,与
extern char **environ;
从版本 7 开始,两者都在 unix 中可用(在版本 6 中没有环境变量)。extern
命名environ
标准化;第三个论点main
没有。main
除了作为某种时尚声明外,没有理由使用 3-arg 。
调用的进程设置代码main
不需要知道 main 是否需要 3 个参数,因为在汇编级别上,接受 2 个参数的函数和接受 3 个参数但不使用第三个参数的函数之间没有区别。或者在一个不带参数的函数和一个带 2 个参数但不使用它们的函数之间,这就是为什么int main(void)
也可以工作的原因。
具有非 unix 类 ABI 的系统可能需要知道main
它们调用的是哪种类型。
把它放在一个文件中:
#include <stdio.h>
int foo(int argc, char **argv)
{
int i;
for(i=0;i<argc;++i)
puts(argv[i]);
return 0;
}
这在另一个:
extern int foo(int argc, char **argv, char **envp);
int main(int argc, char **argv)
{
char *foo_args[] = { "foo", "arg", "another arg" };
char *foo_env[] = { "VAR=val", "VAR2=val2" };
foo(3, foo_args, foo_env);
return 0;
}
从跨平台语言律师的角度来看,这是完全错误的。我们对编译器的类型撒了谎,foo
并给它传递了比它想要的更多的参数。但在unix中,它可以工作。额外的参数只是无害地占用堆栈上的一个槽,该槽在函数返回后由调用者正确解释和清理,或者暂时存在于被调用者不希望找到任何特定内容的寄存器中,并且调用者期望被调用者破坏,因此它不介意寄存器是否在被调用者中被重用于其他目的。
这正是envp
具有 2-arg main 的普通 C 程序中发生的情况。argc
以及argv
在程序中会发生什么int main(void)
。
但就像envp
它本身一样,没有充分的理由在严肃的代码中利用这一点。类型检查对你有好处,知道你可以逃避它应该知道你不应该。