2017-06-11 71 views
1

我想在沒有任何CRT庫的Windows上創建簡單的程序。C++ Windows返回vs ExitProcess

我有兩個代碼:

// compile without -lkernel32 
int __stdcall _main() { 
    return 5; 
} 

// compile with -lkernel32 
#include <windows.h> 

void __stdcall _main() { 
    ExitProcess(5); 
} 

我與編譯它們的MinGW-W64 7.1.0本bash腳本:

@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 

輸出(退出代碼)是一樣的。 (我正在使用Windows 7 Pro 64位)

什麼代碼更好? (也許更好的問題是:爲什麼會出現「返回」變種工作?)

編輯:

入口點到程序(defaultly通過連接預先設定的)是_main(通常CRT lib中做了一些工作,然後調用'主'功能,並調用ExitProcess(或類似的東西)從主函數返回的值)。

在我的代碼中,我沒有使用CRT庫,_main仍然是程序的入口點(並且不調用'main'函數)。

+0

使用'return'變體是可移植的代碼,因此應該是首選。 –

+1

@πάνταῥεῖ - 這不是便攜式的變體,這個錯誤的變體 – RbMm

+0

你還需要看看exit和_exit。 – cup

回答

5

你是正確的,爲什麼return版本的作品關鍵是要理解這是更好的直接調用ExitProcess - 所以唯一的辦法正確終止進程。

這裏重要的是main不是Windows控制檯應用程序的入口點。入口點在庫代碼中,初始化內存,在全局變量上調用構造函數,將命令行分割成argc/argv格式,然後調用main保存返回值。

如果main確實返回,它將返回到調用atexit註冊的函數和析構函數的靜態變量的庫代碼,然後調用ExitProcess

因此,確實只有一種方法來設置退出值,通過調用ExitProcess。但是自己動手會跳過庫所採取的清理操作 - 如果您調用ExitProcess,那麼析構函數不會被調用,並且最終可能會丟失寫入緩衝區中的數據。

當你建立沒有標準庫時,那麼建造/毀壞的庫行爲是不相關的,明確調用ExitProcess幾乎與返回一樣。還有一個庫提供的調用框架可以捕獲你的返回值,如果你不這樣做,調用ExitThread,但是當沒有CRT時它來自操作系統本身(kernel32.dll)。正如RmMb指出的那樣,這是一個重要的區別,因爲其他線程不會被殺死;如果所有線程都退出,該進程將退出。

+0

'沒有任何CRT庫。「 - 因此在這種情況下'main'是exe的入口點 – RbMm

+0

@RbMm:用戶入口點isn' t儘管堆棧中的第一幀,kernel32中仍然有一個操作系統入口點,對吧?只要其地址列在PE頭中,「main」就是「真正的」入口點,但執行仍然不會在那裏開始。 –

+1

是的,不是用戶模式下的第一條指令。但kernel32入口點不會調用'ExitProcess' - 它調用'ExitThread' – RbMm

4

如果您不使用CRT - 您需要直接撥打ExitProcess - 如果沒有這個,您的過程根本無法終止。所以只是返回的變體 - 錯誤的。 它只會在您的進程中有單線程工作,否則進程不會終止。


需要了解How Processes are Terminated

進程執行,直到以下事件之一發生:

  • 過程的任何線程調用ExitProcess的功能

  • 的最後一個線程該過程終止。

  • 任何線程都會調用TerminateProcess函數並處理 進程。

當我們使用CRT它內部調用ExitProcess。當我們不使用CRT - main是你exe的真正入口點。返回後 - 你直接返回到kernel32代碼。內核32代碼調用ExitThread但不是ExitProcess - 這是非常重要的。所以只有在你的進程中沒有其他線程的情況下,你的進程纔會被終止。我們永遠無法承擔這一點。並從Windows 10開始,這通常是虛假的。如果你不使用CRT

+1

我不太明白現在與Windows 10有什麼不同? – a3f

+1

@ a3f -windows 10通常在任何進程中自動創建工作線程,用於「並行」加載dll - 這就是所謂的並行加載器。結果總是在你的應用程序中的幾個線程。只需調用'ExitThread'已經不夠了。然而這個工作線程在閒置30秒之後退出 - 在這種情況下的進程可以在30秒後終止 – RbMm