简体   繁体   English

在 C/C++ 程序中,系统(Windows、Linux 和 Mac OS X)如何调用 main() 函数?

[英]In a C/C++ program, how does the system (Windows, Linux, and Mac OS X) call the main() function?

I am looking for a more technical explanation than the OS calls the function.我正在寻找比操作系统调用该函数更具技术性的解释。

Is there a website or book?有网站或书吗?

The .exe file (or equivalent on other platforms) contains an 'entry point' address. .exe 文件(或其他平台上的等效文件)包含一个“入口点”地址。 To a first approximation, the OS loads the relevant sections of the .EXE file into RAM, and then jumps to the entry point.大致上,操作系统将 .EXE 文件的相关部分加载到 RAM 中,然后跳转到入口点。

As others have said, this entry point will not be 'main', but will instead be a part of the runtime library - it will do things like initialising static objects, setting up the argc and argv parameters, setting up standard input, standard output, standard error, etc. When it's done all that, it will call your main() function.正如其他人所说,这个入口点不会是“主”,而是运行时库的一部分——它会做一些事情,比如初始化静态对象、设置argcargv参数、设置标准输入、标准输出,标准错误等。完成所有这些后,它将调用您的 main() 函数。 When main exits, the runtime goes through an analogous process of passing your return code back to the environment, calling static destructors, calling _atexit routines, etc.当 main 退出时,运行时会经历一个类似的过程,将返回代码传递回环境、调用静态析构函数、调用 _atexit 例程等。

If you have Microsoft tools (perhaps not the freebie ones), then you have all the runtime source, and an easy way to look at it is to put a breakpoint on the closing brace of your main() method, and single step back up into the runtime.如果你有微软工具(也许不是免费的),那么你就有了所有的运行时源,一个简单的查看方法是在你的 main() 方法的右大括号上放一个断点,然后单步备份进入运行时。

main() is part of the C library and is not a system function. main()是 C 库的一部分,不是系统函数。 I don't know for OS X or Linux, but Windows usually starts a program with WinMainCRTStartup() .我不知道 OS X 或 Linux,但 Windows 通常使用WinMainCRTStartup()启动程序。 This symbol init your process, extract command line arguments and environment ( argc, argv, end ) and calls main() .该符号初始化您的进程,提取命令行参数和环境( argc, argv, end )并调用main() It is also responsible of calling any code that should run after main() , like atexit() .它还负责调用应该在main()之后运行的任何代码,例如atexit()

By looking in your Visual Studio file, you should be able to find the default implementation of WinMainCRTStartup to see what it does.通过查看您的 Visual Studio 文件,您应该能够找到WinMainCRTStartup的默认实现以了解它的作用。

You can also define a function of your own to call at startup, this is done by changing "entry point" in the linker options.您还可以定义自己的函数以在启动时调用,这是通过更改链接器选项中的“入口点”来完成的。 This is often a function that takes no arguments and returns a void.这通常是一个不带参数并返回 void 的函数。

As far as Windows goes, the entry point functions are:就 Windows 而言,入口点函数是:

  • Console: void __cdecl mainCRTStartup( void ) {}控制台: void __cdecl mainCRTStartup( void ) {}
  • GUI: void __stdcall WinMainCRTStartup( void ) {}图形用户界面: void __stdcall WinMainCRTStartup( void ) {}
  • DLL: BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved) {} DLL: BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved) {}

The only reason to use these over the normal main , WinMain , and DllMain is if you wanted to use your own run time library.使用它们而不是普通的mainWinMainDllMain的唯一原因是如果您想使用自己的运行时库。 (If you want smaller file size or custom features.) (如果您想要更小的文件大小或自定义功能。)

For custom run-time implementations and other tricks to get smaller PE files, see:有关获取更小的 PE 文件的自定义运行时实现和其他技巧,请参阅:

Expert C++/CLI (查看第 279 页)有非常具体的关于本机、混合和纯 CLR 程序集的不同引导方案的详细信息。

It's OS dependent.它取决于操作系统。 In OS X, there's a frame in the mach header that contains the start address for the EIP (instruction pointer) register.在 OS X 中,mach 标头中有一个帧,其中包含 EIP(指令指针)寄存器的起始地址。

Once the binary is loaded, the OS launches execution from this address:一旦二进制文件被加载,操作系统就会从这个地址开始执行:

cristi:test diciu$ otool -l ./a.out | grep -A 10 LC_UNIXTHREAD
        cmd LC_UNIXTHREAD
    cmdsize 80
     flavor i386_THREAD_STATE
      count i386_THREAD_STATE_COUNT
[..]
        ss  0x00000000 eflags 0x00000000 eip 0x00001f8c cs  0x00000000
[..]

The address is the address of the "start" function from the binary:地址是二进制文件中“start”函数的地址:

cristi:test diciu$ nm ./a.out
0000200c D _NXArgc
00002008 D _NXArgv
00002000 D ___progname
00001fe0 t __dyld_func_lookup
00001000 A __mh_execute_header
[..]
00001f8c T start

In Mac OS X, it's the "start" function that gets called first, even before the "main" function:在 Mac OS X 中,首先调用的是“start”函数,甚至在“main”函数之前:

(gdb) b start
Breakpoint 1 at 0x1f90
(gdb) b main
Breakpoint 2 at 0x1ff4
(gdb) r
Starting program: /Users/diciu/Programming/test/a.out 
Reading symbols for shared libraries ++. done

Breakpoint 1, 0x00001f90 in start ()

If You are interested in a book related to Windows and Win32 API try 如果您对与Windows和Win32 API相关的书感兴趣,请尝试

"Programming Applications for Microsoft Windows" by Jeffrey Richter. Jeffrey Richter编写的“Microsoft Windows编程应用程序”。

You can take a look at following links: 您可以查看以下链接:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM