2017-06-11 12 views
1

CRTライブラリなしでWindows上で簡単なプログラムを作成しようとしています。 (C++ WindowsリターンとExitProcess

@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 

出力:

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

と私はそれらをコンパイルしています

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

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

このbashスクリプトとMinGWの-W64 7.1.0:

は、私は2つのコードを持っています終了コード)は同じです。 (私はWindows 7 Pro 64ビットを使用しています)

どのようなコードが優れていますか? (たぶん、より良い質問です:なぜ「リターン」は、変異体の仕事はしますか?)

編集:

エントリポイントプログラムには、(defaultlyリンカによってあらかじめ設定された)(通常はCRT libには、いくつかの作業を行い、その後、呼び出し、_mainされます'main'関数を呼び出し、ExitProcess(またはそのようなもの)をmain関数から返された値で呼び出します)。

私のコードでは、私はCRTライブラリを使用していませんし、_mainはまだプログラムのエントリポイントです(そして 'main'関数を呼び出さない)。

+0

'return'バリアントを使用すると移植性の高いコードになります。 –

+1

@πάνταῥεῖ - これは移植性のない変種です。間違った変種 – RbMm

+0

exitと_exitも参照する必要があります。 – cup

答えて

5

を使用しない場合は直接呼び出しExitProcess - その唯一の方法は、正しいプロセスを終了します。

ここで重要なことは、mainがWindowsコンソールアプリケーションのエントリポイントではないことです。エントリポイントはライブラリコード内にあり、メモリを初期化し、グローバル変数のコンストラクタを呼び出し、コマンドラインをargc/argvフォーマットに分割し、戻り値を保存するmainを呼び出します。

mainが返された場合、ライブラリコードに戻り、atexit - 登録された静的変数の関数とデストラクタを呼び出し、ExitProcessを呼び出します。

したがって、ExitProcessを呼び出すことによって、終了値を設定する方法は1つだけです。しかし、あなた自身でそれを行うと、ライブラリーで行われたクリーンアップアクションはスキップされます。ExitProcessを呼び出すと、デストラクタが呼び出されず、書き込みバッファにスタックされたデータが失われる可能性があります。

標準ライブラリなしでビルドすると、構築/破壊のライブラリアクションは関係なく、ExitProcessを明示的に呼び出すことは、返すこととほぼ同じです。あなたの戻り値をキャッチし、そうでない場合はExitThreadを呼び出すライブラリ提供の呼び出しフレームがありますが、CRTがない場合はOS自体(kernel32.dll)から呼び出します。 RmMbが指摘するように、これは重要な違いです。他のスレッドは強制終了されないためです。すべてのスレッドが終了すると、プロセスは終了します。

+0

'の後に終了することができます。この場合、' main'はtrueです。exe – RbMm

+0

のエントリポイント@RbMm:ユーザエントリポイントisn'スタック上の最初のフレームは、まだkernel32にOSのエントリポイントがあります。 'main'はアドレスがPEヘッダにリストされている限り「真の」エントリポイントですが、実行はまだ開始されません。 –

+1

はい、ユーザーモードの最初の命令ではありません。カーネル32エントリポイントは 'ExitProcess'を呼び出さない - ' ExitThread'を呼び出す – RbMm

4

使用しない場合CRT - 直接電話ExitProcessを呼び出す必要があります。これがなければ、プロセスはまったく終了できません。変種だけで返品 - 間違っています。 プロセス内の単一のスレッドのみが処理されます。それ以外の場合は処理が終了しません。

  • プロセスのいずれかのスレッドが最後のスレッド

  • のExitProcess関数を呼び出します。


    How Processes are Terminated

    次のいずれかのイベントが発生するまでのプロセスが実行さを理解して必要プロセスは終了する。

  • いずれのスレッドも、 プロセスへのハンドルを使用してTerminateProcess関数を呼び出します。我々はCRTを使用する場合

は、それが内部的にExitProcessを呼び出します。我々が使用しないときCRT - mainあなたのexeの真のエントリポイントです。リターンの後、直接kernel32コードに戻ります。カーネル32のコードの呼び出しExitThreadではなく、ExitProcess - これは非常に重要です。この場合、プロセス内に別のスレッドが存在しない場合に限り、プロセスは終了します。私たちはこれを仮定することはできません。これはいつも間違っている窓10から始まります。あなたはreturnバージョンが動作する理由優れて理解するための鍵であることをあなたは正しいCRT

+1

Windows 10とは何が違うのかよく分かりませんでしたか? – a3f

+1

@ a3f - windows 10通常は、自動的に "parallel"でロードdllのすべてのプロセスで作業スレッドを作成します。これはいわゆる並列ローダーです。その結果、アプリ内には常に複数のスレッドが作成されます。単に 'ExitThread'を呼び出すだけでは十分ではありません。しかしこの場合、30秒のアイドルプロセスの後に終了したこの作業スレッドは、 'CRTライブラリなしで30秒 – RbMm