C++ 如何将命令行参数转换为数组?
Posted
技术标签:
【中文标题】C++ 如何将命令行参数转换为数组?【英文标题】:How C++ turns command line arguments into an array? 【发布时间】:2012-08-27 04:57:36 【问题描述】:我想知道 C++ 如何实际将命令行参数转换为 char 数组?这是什么“秘密”代码?我在哪里可以查看执行此操作的代码(即使它在汇编中,我也知道一些汇编)?我正在使用 Linux,如果有帮助的话。
谢谢
【问题讨论】:
视情况而定。为什么需要知道? 我想知道以帮助我更好地理解编程。 问题是,没有一个答案。对于不同的编译器和不同的系统,它是不同的。如果您正在编写可移植的 C++,那么它根本就不是您关心的事情。 【参考方案1】:它是 c 运行时库的一部分。如果您想知道那是什么,请看这里:What is the C runtime library?
我刚刚使用 Microsoft Visual Studio 创建了一个基本的 C++ 控制台应用程序,并在程序的第一行设置了一个断点。调试时,程序在该行停止,您调用查找调用堆栈以查看调用“main”的函数。调用函数是 c 运行时的一部分,它似乎包含一些操作命令行的代码……我没有仔细看,但这可能是你应该开始的地方。
【讨论】:
您确定这是运行时的一部分吗?我的理解是操作系统这样做了,因为在程序启动时,这些数组的内存已经被分配了。 在 Windows 上 CreateProcess 需要一个 LPTSTR 作为命令行,当你在 C++ 主函数中看到它时,它位于以下参数中:int main(int argc, char *argv[])。我最好的估计是,在两者之间,C 运行时通过拆分进程的命令行参数来进行转换。 它不是 C 运行时库的一部分。 C(和 C++)指定的只是如何调用main
函数。命令行参数是如何形成的,以及程序启动时如何调用main
,这两个标准都没有规定。
@DavidHammen C 和 C++ 标准没有指定如何实现运行时库。因此,某些 C 和 C++ 运行时库解析命令行并将它们转换为 argc/argv
是完全合理的。 MSVC 就是这样一个例子。【参考方案2】:
这通常由操作系统在为程序创建进程时处理。这段代码很可能是用 C 编写的(例如,如果操作系统是用 C 编写的),也可以是汇编代码。要找到它的代码,您可能需要查看操作系统代码。
希望这会有所帮助!
【讨论】:
在 Windows 上由语言运行时完成。不确定 *nix 系统。 在 Windows 上,CRT 执行此操作;在类 Unix 系统上,它是由一个 shell 或另一个启动进程的程序来完成的。我不知道任何自己解析命令行的操作系统。 @hamstergene 我同意。说这是“通常”由操作系统完成似乎有点牵强。【参考方案3】:有时它不是首先执行的实际main()
。例如,在 Visual Studio 上,函数 mainCRTStartup()
用作调用 Windows API 以检索和解析命令行的入口点(如果使用调试器,您可以看到这一点)。
【讨论】:
我认为它使用 GetCommandLine 和 CommandLineToArgvW API。【参考方案4】:在大多数(全部?)基于 Unix 的操作系统中,它们已经是一个数组。这就是操作系统在那里执行进程的方式——当一个进程启动时,已经有一组参数可供它使用。
将命令行转换为数组的代码位于 shell(如 bash)或启动另一个程序的任何其他程序中。 bash
有它的资源可用,其他程序 - 它是不同的。
在 Windows 中,它们是一个字符串(您可以使用 GetCommandLine()
API 调用将其保持不变),由 C 运行时库解析以将其转换为数组,因为语言规范要求它们以数组的形式出现。
对于使用 Visual C++ 编译的程序,执行此操作的代码包含在 Visual Studio 发行版中。您可能必须在安装程序中打开一个显示“包含 C 运行时库源”之类的复选框才能安装它。
【讨论】:
不,环境和参数由内核复制。 @EarlGray 不——对什么?问题是命令行是如何被解析成数组的,而不是后来谁复制了数组。【参考方案5】:管理命令行参数并在进程创建期间将其放入堆栈是一项操作系统工作。
对于 POSIX 系统,执行路径是:
-
在您的程序中调用 execle/execve/... 系统调用,传递新进程可执行文件和命令行参数的路径。
这些数据进入内核
内核更新其内部结构以考虑新进程标识并为新进程分配地址空间(如果不再需要旧地址空间,内核也会清除它)。内核用零初始化进程内存,将信息从旧内存复制到堆栈顶部的新地址空间。
内核将新进程放入调度队列并从
exec()
系统调用返回,将执行路径转移到用户空间并最终到达进程的入口点(这通常是来自crt0.o
目标文件的例程,默认情况下链接到每个可执行文件 - 此例程调用 main()
)。
对于 Linux,您可以在此处查看此代码: http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/fs/exec.c#L383:
383 /*
384 * 'copy_strings()' copies argument/environment strings from the old
385 * processes's memory to the new process's stack. The call to get_user_pages()
386 * ensures the destination page is created and not swapped out.
387 */
在用户空间 execve()
系统调用的 do_execve()
内核对应项中,在第 1345 行,copy_strings()
被调用,copy_strings()
例程实际上完成了您所询问的工作。
【讨论】:
“copy_strings() 例程实际上完成了您所要求的工作” - 他所说的过程是将命令字符串转换为数组。copy_strings
函数中不会发生这种情况 - 该命令在该函数接触它之前已经是一个数组。
我将问题理解为“如何创建新进程内存中的 char 数组 argv[]”,因为从 C 代码调用 execve() 已经需要一个数组。所以,是的,从您的角度来看,它是一个将命令行分开的 shell,但该代码非常原始。以上是关于C++ 如何将命令行参数转换为数组?的主要内容,如果未能解决你的问题,请参考以下文章