我试图在没有任何CRT库的Windows上创建简单的程序.
我有两个代码:
// compile without -lkernel32
int __stdcall _main() {
return 5;
}
Run Code Online (Sandbox Code Playgroud)
和
// compile with -lkernel32
#include <windows.h>
void __stdcall _main() {
ExitProcess(5);
}
Run Code Online (Sandbox Code Playgroud)
我用这个bash脚本用MinGW-w64 7.1.0编译它们:
@echo off
del main.exe 2>nul
C:\Users\Michal\Downloads\mingw64\bin\g++ main.cpp -o main.exe -O3 -s -nostdlib -lkernel32
main.exe
echo %errorlevel%
pause
Run Code Online (Sandbox Code Playgroud)
输出(退出代码)是相同的.(我使用的是Windows 7 Pro 64位)
什么代码更好?(也许更好的问题是:为什么"返回"变体有效?)
编辑:
程序的入口点(默认由链接器预先设置)是_main(通常CRT lib执行一些工作然后调用'main'函数并使用main函数返回的值调用ExitProcess(或类似的东西)).
在我的代码中,我没有使用CRT库,_main仍然是程序的入口点(并没有调用'main'函数).
你是正确的,为什么return版本的工作是理解哪个更好的关键.
这里重要的是它main不是Windows控制台应用程序的入口点.入口点在库代码中,初始化内存,在全局变量上调用构造函数,将命令行拆分为argc/ argvformat,然后调用main保存返回值.
如果main确实返回,则返回库代码,该代码调用atexit静态变量的注册函数和析构函数,然后调用ExitProcess.
因此,实际上只有一种方法可以通过调用来设置退出值ExitProcess.但是自己动手会跳过库所采取的清理操作 - 如果你调用ExitProcess那么析构函数就不会被调用,你可能最终会丢失写入缓冲区中的数据.
当您在没有标准库的情况下构建时,构造/销毁的库操作不相关,并且ExitProcess显式调用与返回几乎相同.还有一个库提供的调用框架可以捕获您的返回值,ExitThread如果不这样,则调用它,但是当没有CRT时,它来自操作系统本身(kernel32.dll).正如RmMb指出的那样,这是一个重要的区别,因为其他线程不会被杀死; 如果所有线程都退出,进程将退出.
如果您不使用CRT - 您需要直接呼叫ExitProcess- 如果没有这个,您的过程根本无法终止.如此变种只返回 - 错误.只有当你的进程中有单个线程时它才会起作用,否则进程不会终止.
需要了解进程如何终止
进程将执行,直到发生以下事件之一:
进程的任何线程都调用ExitProcess函数
该进程的最后一个线程终止.
任何线程都使用进程句柄调用TerminateProcess函数.
当我们使用CRT时,它在内部调用ExitProcess.当我们不使用CRT时 - main是你的exe的真正切入点.返回后 - 直接返回kernel32代码.内核32代码调用ExitThread但不是ExitProcess- 这非常重要.因此,只有在您的流程中没有其他线程时,您的流程才会在此情况下终止.我们永远不能假设这一点.并且从Windows 10开始,这通常都是假的.所以只有这样才能正确终止进程 - ExitProcess如果不使用CRT则直接调用