命令行参数是如何工作的?

5

正如问题所提到的,如何在C(通常是任何语言)中使用命令行参数。我能想到的逻辑解释是,操作系统在启动进程时为其设置某种环境值。

但如果这是真的,我就不应该能够像argp[i]等方式访问它们(我修改了main函数,以便期望第二个参数为char ** argp而不是** argv)。请解释一下。


2
你为什么认为你不能像 argp[i] 一样访问它们?(请注意,函数参数名称通常在编译后的程序中没有意义,将第二个参数命名为 main 的 argv 只是一种约定,如果你愿意,你可以将其命名为 FOOBAR) - nos
1
main 函数的参数与其他函数的参数一样。名称并不重要,即使在函数原型和实际函数中使用不同的参数名称,只要类型匹配即可。main 函数的参数来源并不重要,只需将它们视为整数和指针数组(或在您的情况下是指向指针的指针)即可。 - Some programmer dude
3个回答

10

我会尽量比其他答案更详细地解释实现过程。
虽然可能存在不准确之处,但希望它足以描述相关部分。

在Shell下, 您输入./myprog a b c.
Shell解析它,并确定你想要用三个参数运行./myproj.
它调用fork创建一个新的进程,在那里./myprog将运行。
子进程仍在运行Shell程序,它准备了一个由5个字符指针组成的数组。第一个指向字符串./prog,接下来的三个指向字符串a, bc,最后一个被设置为NULL。
接下来,它调用execve函数,使用创建的参数数组运行./myprog
execve加载./myprog到内存中,而不是Shell程序。它释放Shell程序分配的所有内存,但确保保留参数数组。
在新程序中,main被调用,并将参数数组作为argv传递给它。


为什么execve不需要argc参数? - Agnel Kurian
实际上,该数组将包含五个条目,请不要忘记在第一(零)个位置中放置程序名称。 - Some programmer dude
1
它可能使用除fork-exec之外的其他机制来实际创建新进程。这完全取决于操作系统,对于本问题的目的来说并不重要。无论操作系统和shell用什么机制来运行命令,都必须涉及传递命令行参数。这是类UNIX方式的做事方式,其中参数由fork“克隆”并由execve“保留”。 - Steve Jessop
@SteveJessop,你说得对,我解释了一种可能不准确描述任何操作系统的实现方式。但是,我认为描述一个简单的机制,这个机制经常被使用,会比仅仅说你保证得到什么更有助于理解问题。 - ugoren
@ugoren:我同意,具体的例子非常有用。定义的行为只是,“在进入main时正确的数组显示出来”,这并没有说明任何问题;-) - Steve Jessop

5
在C程序中,操作系统创建一个指向零终止字符串的指针数组。计数作为argc传递,数组作为argv传递。您已经知道这一点。名称argcargv并不重要。您可以使用任何名称。数据类型和顺序很重要... argv 必须是 int argc 必须是 char * [] char ** 。其他语言也有类似的机制。例如,C#传递单个 string [] 参数,它是.NET数组,并在内部跟踪其长度。有关更多信息,请参见此处
环境变量名称与程序中变量的名称不同。 argc argv 不是环境变量...它们是本地变量 main()
要访问环境变量,请使用 getenv()更新:您想知道如何将其提供给程序。这是操作系统所做的。但是,在操作系统能够这样做之前,调用可执行文件的程序(调用方)会处理您的命令行。通常,调用方是一个shell( bash csh zsh cmd.exe )或桌面环境,例如GNOME或Windows Explorer。调用方通过execve(在*nix上)或CreateProcess(在Windows上)传递这些参数。

2
无论你给主要参数取什么名字,重要的是它们的类型和顺序。要获取环境变量,请使用这个闭包:
int main(int argc, char ** myCommandLineArguments, char ** myEnvironmentVars)

这是你想知道的吗?


谢谢您的回答。实际上,我的问题不是关于如何访问它们,而是关于谁以及如何将它们提供给程序使用的。 - Thunderman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接