在 C/C++ 程序中,系统(windows、linux、mac OS X)如何调用 main() 函数?
Posted
技术标签:
【中文标题】在 C/C++ 程序中,系统(windows、linux、mac OS X)如何调用 main() 函数?【英文标题】:In a C/C++ program how does the system (windows, linux, mac OS X) call the main() function? 【发布时间】:2010-09-05 22:55:01 【问题描述】:我正在寻找更技术性的解释,然后操作系统调用该函数。
任何人都可以帮助我或将我指向一个网站或书籍吗?
【问题讨论】:
谁投票关闭?这个问题对我来说似乎完全有效。这是个好问题!!! 我投票结束这个问题,因为它是“寻求有关书籍、工具、软件库等的建议:这个问题可能会导致基于意见的答案”。 【参考方案1】:就 windows 而言,入口点函数是:
控制台:void __cdecl mainCRTStartup( void )
界面:void __stdcall WinMainCRTStartup( void )
DLL:BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved)
在普通 main/WinMain/DllMain 上使用它们的唯一原因是如果您想使用自己的运行时库(如果您想要更小的文件大小或自定义功能)
有关自定义运行时实现和其他获取更小的 PE 文件的技巧,请参阅:
http://www.microsoft.com/msj/archive/S569.aspx http://www.codeproject.com/KB/tips/aggressiveoptimize.aspx http://www.catch22.net/tuts/minexe.asp http://www.hailstorm.net/papers/smallwin32.htm【讨论】:
【参考方案2】:它取决于操作系统。 在 OS X 中,mach 标头中有一个帧,其中包含 EIP(指令指针)寄存器的起始地址。
一旦二进制文件被加载,操作系统就会从这个地址开始执行:
cristi:test diciu$ otool -l ./a.out | grep -A 10 LC_UNIXTHREAD cmd LC_UNIXTHREAD cmdsize 80 风味 i386_THREAD_STATE 计数 i386_THREAD_STATE_COUNT [..] ss 0x00000000 eflags 0x00000000 eip 0x00001f8c cs 0x00000000 [..]地址是二进制中“start”函数的地址:
cristi:test diciu$ nm ./a.out 0000200c D_NXArgc 00002008 D_NXArgv 00002000 D ___程序名 00001fe0 t __dyld_func_lookup 00001000 A __mh_execute_header [..] 00001f8c T 开始在 Mac OS X 中,首先调用的是“start”函数,甚至在“main”函数之前:
(gdb) b 开始 0x1f90 处的断点 1 (gdb) b 主要 0x1ff4 处的断点 2 (gdb) r 启动程序:/Users/diciu/Programming/test/a.out 共享库 ++ 的读取符号。完毕 断点 1, 0x00001f90 in start()【讨论】:
【参考方案3】:Expert C++/CLI(查看第 279 页)非常详细地介绍了本机、混合和纯 CLR 程序集的不同引导方案。
【讨论】:
【参考方案4】:.exe 文件(或其他平台上的等效文件)包含一个“入口点”地址。大致上,操作系统将 .EXE 文件的相关部分加载到 ram 中,然后跳转到入口点。
正如其他人所说,这个入口点不会是“main”,而是运行时库的一部分——它会做一些事情,比如初始化静态对象、设置 argc/argv 参数、设置 stdin/ stdout/stderr 等。完成所有这些后,它将调用您的 main() 函数。当 main 退出时,运行时会经历一个类似的过程,将返回代码传回环境、调用静态析构函数、调用 _atexit 例程等。
如果你有 MS 工具(也许不是免费的),那么你就有了所有的运行时源,一个简单的查看方法是在你的 main() 方法的右大括号上放一个断点,然后单退回到运行时。
【讨论】:
【参考方案5】:main()
是 C 库的一部分,不是系统函数。我不知道 OS X 或 Linux,但 Windows 通常以WinMainCRTStartup()
启动程序。这个符号初始化你的进程,提取命令行参数和环境(argc, argv, end
)并调用main()
。它还负责调用应该在main()
之后运行的任何代码,例如atexit()
。
通过查看您的 Visual Studio 文件,您应该能够找到 WinMainCRTStartup
的默认实现以了解它的作用。
您还可以定义自己的函数以在启动时调用,这是通过更改链接器选项中的“入口点”来完成的。这通常是一个不带参数并返回 void 的函数。
【讨论】:
以上是关于在 C/C++ 程序中,系统(windows、linux、mac OS X)如何调用 main() 函数?的主要内容,如果未能解决你的问题,请参考以下文章
Windows 下使用 VScode 运行 C/C++ 程序