OpenSiv3DのMain関数
こんにちは、めのんです!
昨日からC++の勉強を兼ねてOpenSiv3Dを触り始めました。 C++の主だった文法は一通り把握できたと自分では思っているんですけど、まだまだ場数を踏まないと自由に操れるところまではいきません。 そういうわけで、OpenSiv3Dを題材にいろいろやってみようと思っています。
私はよくわからないままとりあえず動くものを作るというのがあまり得意ではありません。 PHPの勉強でもそうなのですが、疑問に思ったところを徹底的に調べて、それから作り始めるのが好きなんです。
プログラミング初学者の方にはあまりお勧めできない方法ですね。 私はもともとハードウェアの技術者で、最初に仕事でプログラミングをやったのもアセンブリ言語でしたから、徹底的に調べてからプログラミングするやり方ができたんだと思います。
さて、今回はOpenSiv3DのMain関数についてです。
普通、C++のプログラムはmain関数から始まります。 これはCと同じなので私にもなじみがあります。 ところが、OpenSiv3DではMain関数を使います。 頭文字の「M」が大文字なのでmainとは別の関数です。
最初これを見たとき、WindowsだとWnMainやwWinMainを使うので互換性のためにそうしたのかな? と思っていました。 仮引数を受け取らないので、コマンドライン引数を扱う場合はWindowsとそれ以外でコードを分けないといけないのが面倒だな? とも思いました。 あとはせいぜい例外やシグナルをケアする程度だろうなとも思っていました。
ところが、Windows Desktop用のMainを呼び出すコードを見ると、確かにそういった要素もありましたが予想に反した内容でした。 ここでWinMain関数を引用してみたいと思います。
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { //_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); SIMPLE_LOG(U"WinMain"); SIMPLE_LOG(U"Siv3D for Windows"); using namespace s3d; ScopeGuard onExit = [](){ cv::DeleteInitializationMutex(); }; Siv3DEngine engine; try { Siv3DEngine::Get<ISiv3DSystem>()->init(); } catch (const EngineError& error) { const String text = U"EngineError: {}"_fmt(error.what()); LOG_ERROR(text); EngineMessageBox::Show(text); return -1; } LOG_TRACE(U"MainThread"); Logger.writeRawHTML_UTF8("<hr width=\"99%\">"); { const std::future<void> f = std::async(std::launch::async, MainThread); while (!f._Is_ready()) { PumpMessages(); ::timeBeginPeriod(1); ::Sleep(1); ::timeEndPeriod(1); } } Logger.writeRawHTML_UTF8("<hr width=\"99%\">"); return 0; }
Main関数は後半に登場するstd::async関数に与えているMainThread関数から呼び出されます。 std::launch::asyncを指定しているので別のスレッドでMain関数は呼び出されるようなのです。
一方で、macOSやLinux用のmain関数の実装を見てみると、最初に私が予想したのとほぼ同じ感じで、main関数から直接Main関数が呼び出されていました。 どうしてWindowsだけは別スレッドで動かしているのか、私はWindowsにもそんなに詳しくないのでよくわかりませんでした。 まだまだ精進が必要そうですね。
それでは!!