C++ Windows返回vs ExitProcess

Mic*_*bek 2 c++ winapi

我试图在没有任何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'函数).

Ben*_*igt 6

你是正确的,为什么return版本的工作是理解哪个更好的关键.

这里重要的是它main不是Windows控制台应用程序的入口点.入口点在库代码中,初始化内存,在全局变量上调用构造函数,将命令行拆分为argc/ argvformat,然后调用main保存返回值.

如果main确实返回,则返回库代码,该代码调用atexit静态变量的注册函数和析构函数,然后调用ExitProcess.

因此,实际上只有一种方法可以通过调用来设置退出值ExitProcess.但是自己动手会跳过库所采取的清理操作 - 如果你调用ExitProcess那么析构函数就不会被调用,你可能最终会丢失写入缓冲区中的数据.

当您在没有标准库的情况下构建时,构造/销毁的库操作不相关,并且ExitProcess显式调用与返回几乎相同.还有一个库提供的调用框架可以捕获您的返回值,ExitThread如果不这样,则调用它,但是当没有CRT时,它来自操作系统本身(kernel32.dll).正如RmMb指出的那样,这是一个重要的区别,因为其他线程不会被杀死; 如果所有线程都退出,进程将退出.


RbM*_*bMm 5

如果您不使用CRT - 您需要直接呼叫ExitProcess- 如果没有这个,您的过程根本无法终止.如此变种只返回 - 错误.只有当你的进程中有单个线程时它才会起作用,否则进程不会终止.


需要了解进程如何终止

进程将执行,直到发生以下事件之一:

  • 进程的任何线程都调用ExitProcess函数

  • 该进程的最后一个线程终止.

  • 任何线程都使用进程句柄调用TerminateProcess函数.

当我们使用CRT时,它在内部调用ExitProcess.当我们不使用CRT时 - main是你的exe的真正切入点.返回后 - 直接返回kernel32代码.内核32代码调用ExitThread但不是ExitProcess- 这非常重要.因此,只有在您的流程中没有其他线程时,您的流程才会在此情况下终止.我们永远不能假设这一点.并且从Windows 10开始,这通常都是假的.所以只有这样才能正确终止进程 - ExitProcess如果不使用CRT则直接调用

  • @ a3f-Windows 10通常会在任何进程中自动为“并行”中的加载dll创建工作线程-这就是所谓的并行加载器。结果,您的应用程序中总是有多个线程。仅仅调用`ExitThread`还不够。但是,此工作线程在空闲30秒后退出-在这种情况下,进程可以在30秒后终止 (2认同)