为啥 main(int argc, char* argv[]) 需要两个参数? [复制]

Posted

技术标签:

【中文标题】为啥 main(int argc, char* argv[]) 需要两个参数? [复制]【英文标题】:Why does main(int argc, char* argv[]) take two argument? [duplicate]为什么 main(int argc, char* argv[]) 需要两个参数? [复制] 【发布时间】:2015-11-07 02:34:28 【问题描述】:

我一直认为argc 必须用来标记argv 的结束,但我刚刚了解到argv[argc] == NULL 的定义。我认为argc 是完全多余的吗?如果是这样,我一直认为C 以效率的名义消除了冗余。我的假设是错误的还是背后有历史原因?如果原因是历史性的,您能详细说明吗?

【问题讨论】:

NULL 不能是argv 的元素吗?也就是说,在数组的实际结束之前。 @AndrasDeak,我不这么认为。 argv 的元素可以是一个空字符串,即一个只有一个元素的数组,0-byte。 是的,它是多余的。原因是“历史原因” 加上if (argc < 3) printf("error message"); return 1; 无需先循环argv 列表的能力。更不用说可能基于参数数量做出的各种其他选择(从命令行参数读取文件与读取标准输入等) @Nighthawk441 您可以将其称为execname 'arg1' 'arg2' '' 'arg4',在这种情况下argv[3] 是一个空字符串。而且,正如@Jens 所说,那不是NULL 【参考方案1】:

历史。

Harbison & Steel(第 5 版,9.9“主程序”)说明如下:

标准 C 要求 argv[argc] 为空指针,但在某些较旧的实现中并非如此。

【讨论】:

了解哪些“旧实现”没有argv[argc] 作为空指针会很有帮助——不过,我怀疑 H&S 没有提供这种详细程度。这些天他们一定很老了。 (我从来没有不幸遇到过一个,但是有很多深奥的平台我没有在上面编程过。) FWIW 我设法找到了 K&R 第 1 版的扫描 PDF,据我所知,他们从未在 argv[argc] 提及空前哨,所有示例都使用 argc 来确定他结束argv[] 数组。第 2 版指出了 null sentinel,但没有在任何示例中使用它。【参考方案2】:

这是历史。

在 C 之前的第一版 UNIX 中,exec 将文件名和指向以 NULL 指针终止的以 NUL 结尾的参数字符串的指针列表的地址作为参数。从手册页:

sys exec; name; args      / exec = 11.
name: <...\0>
...
args: arg1; arg2; ...; 0
arg1: <...\0>
...

内核对参数进行计数,并为新图像提供 arg 计数,然后在堆栈顶部提供指向参数字符串副本的指针列表。从手册页:

sp--> nargs
      arg1
      ...
      argn

arg1: <arg1\0>
...
argn: <argn\0>

(内核源代码是here;我没有看内核是否真的在指向最后一个参数的指针之后写了一些东西。)

在第 6 版之前的某个时间点,exec、execl 和 execv 的文档开始注意到内核在 arg 指针之后放置了一个 -1。手册页说:

Argv 不能直接在另一个 execv 中使用,因为 argv[argc] 是 -1 而不是 0。

此时,您可能会争辩说argc 是多余的,但一段时间以来,程序一直在使用它,而不是查看-1 的参数列表。比如这里是cal.c的开头:

main(argc, argv)
char *argv[];

    if(argc < 2) 
        printf("usage: cal [month] year\n");
        exit();
    

在第 7 版中,exec 已更改为在参数字符串后添加一个 NULL 指针,然后是指向环境字符串的指针列表和另一个 NULL。手册页说:

argv 可以直接在另一个 execv 中使用,因为 argv[argc] 为 0。

【讨论】:

以上是关于为啥 main(int argc, char* argv[]) 需要两个参数? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

int main(int argc, char* argv[]) 和 int main(int argc, char** argv) [关闭]

int main(int argc, char * argv[]) 里的异常处理

int main(int argc,char *argv[])参数的应用

main (int argc,char *argv[]) 或main (int argc,char **argv)区别

int main(int argc,char *argv[])与int main(int argc,char **argv)区别?

int main(int argc,char *argv[]) 解释