17

これは、少なくとも 2 つの密接に関連しているが異なる質問のシリーズの一部です。別々に尋ねることで、正しいことをしていると思います。

Visual C++ 2008 アプリを C ランタイム ライブラリなしで動作させようとしています。これは、MFC やその他の凝ったものを使用せず、単純な Windows API だけの Win32 GUI アプリです。

そこで、Project Properties -> Configuration -> C/C++ -> Advanced -> Omit Default Library Names を Yes (コンパイラ フラグ/Zl) に設定し、再ビルドしました。

次に、リンカーは未解決の外部について不平を言い_WinMainCRTStartupます。もちろん、リンカに別のエントリ ポイントを使用するように指示することもできますMyStartup。Web で収集したものから、いくつかの初期化を行います。おそらくそのサブセットを実行し_WinMainCRTStartupたいと考えています。MyStartup

だから私の質問は次のとおりです。どの機能が_WinMainCRTStartup実行され、CRT を使用しない場合、これらのどれを省略できますか?

あなたがこのことについて知識があるなら、私の他の質問も見てください。ありがとう!

余談: そもそもなぜこれをやりたいのですか?

  1. 私のアプリは、CRT 関数を明示的に使用していません。
  2. 私は無駄のないアプリが好きです。
  3. 新しいことを教えてくれます。
4

3 に答える 3

8

CRTのエントリポイントは次のことを行います(このリストは完全ではありません)。

  • CRTに必要なグローバル状態を初期化します。これを行わないと、CRTが提供する機能や状態を使用できなくなります。
  • コンパイラーによって使用されるグローバル状態を初期化します。/GSで使用されるセキュリティCookieなどの実行時チェックは間違いなくここで際立っています。ただし、自分で__security_init_cookieを呼び出すことはできます。他のランタイムチェックのために他のコードを追加する必要があるかもしれません。
  • C++オブジェクトでコンストラクターを呼び出します。C ++コードを記述している場合は、これをエミュレートする必要があります。
  • コマンドラインを取得し、OSから提供された情報を起動して、メインに渡します。デフォルトでは、OSによってプログラムのエントリポイントにパラメータが渡されることはありません。これらはすべてCRTによって提供されます。

CRTソースコードはVisualStudioで利用でき、デバッガーでCRTのエントリポイントをステップスルーして、CRTが何をしているのかを正確に知ることができます。

于 2009-10-17T21:11:27.497 に答える
7

C (C++ ではない) で書かれた真のWin32 プログラムは初期化をまったく必要としないため、 WinMain(HINSTANCE,...)の代わりにWinMainCRTStartup()でプロジェクトを開始できます。

コンソール プログラムを真の Win32 アプリケーションとして作成することも可能ですが、少し難しくなります。エントリ ポイントのデフォルト名は_mainCRTStartup()です。

スタック プローブ、配列チェックなどの余分なコード生成機能をすべて無効にします。デバッグは引き続き可能です。

初期化

最初のHINSTANCEパラメータが必要な場合があります。Win32 (Win32s を除く) の場合、(HINSTANCE)0x400000に固定されています。

nCmdShowパラメータは常にSW_SHOWDEFAULTです

必要に応じて、 GetCommandLine()でコマンド ラインを取得します。

終了

たとえばGetOpenFileName()を呼び出してプログラムがスレッドを生成する場合、returnキーワードを指定してWinMainCRTStartup()から戻ると、プログラムがハングします —代わりにExitProcess()を使用してください。

注意事項

次の場合、かなりの問題が発生します。

  • 4 KB を超えるスタック フレーム (つまり、ローカル変数) を使用する (関数あたり)
  • 浮動小数点演算の使用 (例: float->int 変換)
  • 32 ビット マシンで 64 ビット整数を使用する (乗算、ビット シフト演算)
  • C++のnewdelete、および static オブジェクトを非ゼロ出力全メンバー コンストラクターで使用する
  • もちろん、 fopen()printf()などの標準ライブラリ関数を使用する

トラブルシューティング

すべての Windows システム (Windows 95 以降) で使用可能な C 標準ライブラリ、MSVCRT.DLLがあります。

これを使用するには、msvcrt-light.lib (google) などを使用してエントリ ポイントをインポートします。ただし、特に MSVC6 よりも新しいコンパイラを使用する場合は、いくつかの注意事項があります。

  • スタック フレームは引き続き 4 KB に制限されます
  • _ftol_sseまたは_ftol2_sseは_ftolにルーティングする必要があります
  • _iob_funcは_iobにルーティングする必要があります

その初期化はロード時に実行されるようです。少なくともファイル機能はシームレスに実行されます。

于 2012-10-10T13:21:08.223 に答える
6

古い質問ですが、答えが間違っているか、特定の問題に焦点を当てています。

プログラムが実際に main/WinMain で開始された場合、Windows (またはほとんどのオペレーティング システム) では使用できない C および C++ 機能がいくつかあります。

次の簡単な例を見てください。

class my_class
{
public:
    my_class() { m_val = 5; }
    int my_func(){ return m_val }
private:
    int m_val;
}

my_class g_class;

int main(int argc, char **argv)
{
     return g_class.my_func();
}

このプログラムが期待どおりに機能するには、my_class のコンストラクターを main の前に呼び出す必要があります。プログラムが正確に main で開始された場合、main の最初に関数呼び出しを挿入するためにコンパイラ ハック (注: GCC がこれを行う場合があります) が必要になります。代わりに、ほとんどの OS では、ほとんどの場合、別の関数が g_class を構築してから main を呼び出します (Windows では、これは mainCRTStartup または WinMainCRTStartup のいずれかです。私が慣れている他のほとんどの OS では、_start という関数です)。

他にも、C++ や C でさえ、main が機能する前または後に実行する必要があるものがあります。メインが起動するとすぐに stdin と stdout (std::cin と std::cout) はどのように使用できますか? atexit はどのように機能しますか?

C 標準では、標準ライブラリに POSIX のようなシグナル API が必要です。これは、Windows では main() の前に「インストール」する必要があります。

ほとんどの OS では、システム提供のヒープはありません。C ランタイムは独自のヒープを実装します (Microsoft の C ランタイムは Kernel32 ヒープ関数をラップするだけです)。

main、argc、および argv に渡される引数でさえ、何らかの方法でシステムから取得する必要があります。

これが Windows + MSVC でどのように機能するかの詳細については、彼自身の C ランタイムの実装に関する Matt Pietrick の (古代の) 記事を参照してください (注: MinGW と Cygwin は特定のものを異なる方法で実装しますが、実際にはほとんどのことで MSVCRT にフォールバックします) ): http://msdn.microsoft.com/en-us/library/bb985746.aspx

于 2014-03-31T03:33:18.160 に答える