正在浏览this site上提供的sudo的源代码,并遇到了这个超级奇怪的类型签名(Bonus问题:对于“类型签名”,是否有更像C的术语?)for main:< / p>
int
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
据我所知,风格本身就是oldskool K&amp; R.我真正感兴趣的是,主要是奖金论点,char **envp
。为什么? sudo是一个相当标准的命令行工具,可以这样调用。当操作系统遇到未使用通常(int argc, char *argv[])?
很多时候,我自己一直懒惰,完全放弃了论点,无论我写的任何程序看起来都运行得很好(C可能会发生最危险的事情,我知道:p)
我的问题的另一部分是,所有这些让你做的很酷的东西?我有一种预感它可以帮助堆积嵌入式编程,但我很遗憾地接触到了这种情况,并且无法真正说出来。 我很想看到一些具体的例子
答案 0 :(得分:1)
http://en.wikipedia.org/wiki/Main_function
从第一段开始:
C和C ++标准也允许其他依赖于平台的格式,除了在C ++中返回类型必须始终为int; [3]例如,Unix(尽管不是POSIX.1)和Microsoft Windows有第三种格式给出程序环境的参数,否则可以通过stdlib.h中的getenv访问:
Google是你的朋友。此外,在这种情况下,操作系统不需要知道关于main的任何内容 - 它是编译器完成工作,只要它是编译器接受的有效参数,就没有问题。
答案 1 :(得分:1)
它只是指向环境的指针,与
相同extern char **environ;
自版本7以来,两者都在unix中可用(版本6中没有环境变量)。名为extern
的{{1}}已标准化; environ
的第三个参数没有。除了某种时尚陈述外,没有理由使用3-arg main
。
调用main
的进程设置代码不需要知道main是否需要3个参数,因为在带有2个参数的函数和带有3个参数的函数之间的汇编级别没有区别但是没有不要使用第三个。或者在不带参数的函数和带有2个参数且不使用它们的函数之间,这就是为什么main
也可以工作的原因。
具有非类似unix的ABI的系统可能需要知道他们正在调用哪种int main(void)
。
将其放在一个文件中:
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;
}
的类型,并传递了比它想要的更多的参数。但在unix中,它可行。额外的参数只是无害地占用堆栈上的一个槽,在函数返回后由调用者正确地计算和清理,或者临时存在于被调用者不期望特别找到任何内容的寄存器中,以及调用者期望被调用者破坏,所以它不介意寄存器是否被重用于被调用者的其他目的。
这正是具有2-arg main的普通C程序中foo
所发生的情况。在envp
的程序中argc
和argv
会发生什么。
但就像int main(void)
本身一样,没有充分的理由在严肃的代码中利用这一点。类型检查对你有好处,并且知道你可以逃避它,应该知道你不应该。