TL;DR:プログラムは C ランタイム ライブラリの複数のバージョンを使用しています。そうしないでください。それ以外の場合は正しいコードから、常に不思議な症状が発生します。
バックグラウンド
一見すると、提示したコードは機能するはずです。そして、ここで慎重に構築してリンクすれば、機能させることができます。参考までに、Win7 Pro で 32 ビット Windows 用の MingW GCC 4.7.2 を使用してビルドしています。しかし、根本的な問題は、Windows を対象とするコンパイラで発生する可能性があると思います。
このバグを発見するプロセスを順を追って説明します。これがどのように解決したかを理解するのに役立つことを願っています。しかし、せっかちな場合は、最後までスキップしてから、ここに戻ってきて、どうやってそこにたどり着いたかを確認してください.
テスト可能なコード
まず、コード フラグメントを十分なボイラー プレートでラップして、コンパイルして実行できるようにしました。
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv) {
AllocConsole();
FILE *fp = freopen("CONOUT$", "w", stdout);
lua_State *L = luaL_newstate();
luaL_openlibs(L);
if(luaL_dostring(L,
"print 'print works!'\n"
"io.write 'io.write works'"
))
{
printf("%s\n", lua_tostring(L, -1));
}
Sleep(5000); // give me 5 seconds to read the console
}
GCC でのコンパイル
Windows で可能な限り簡単にコンパイルしてリンクしましたが、Lua for Windows のコピーがインストールされているため、たまたま環境変数LUA_DEV
がそのインストール先を指しているままになっているため、それほど悪くはありません。
gcc -o q15787892 q15787892.c -mwindows -I"%LUA_DEV%\include" "%LUA_DEV%\lua5.1.dll"
このフラグは、実行可能ファイルを完全な Windows GUI プログラムとしてマークするように-mwindows
GCC (具体的には linker ) に指示します。ld
そのフラグがないと、既にコンソールが割り当てられているコンソール プログラムを取得し、AllocConsole() は、コマンド プロンプトを保持しているコンソールにハンドルを提供するだけです。
結果
興味深いことに、呼び出しでprint()
もio.write()
生成された出力でもありません。Lua テキストに構文エラーを導入し、それがコンソールに出力されたことに注目しました。これは、stdout
実際に正しくリダイレクトされたことを示しています。
FILE *old=stdout;
呼び出しの前後freopen()
に追加しましprintf("%p %p %p", fp, stdout, oldstdout);
た。3 つのポインターはすべて正確に等しく、freopen()
異常なことをしていないことがわかります。
Lua 5.1 のprint()
関数実装のソースを調べると、単純に を呼び出していることがわかりますfputs(s,stdout)
。
printf()
では、 fromへの呼び出しはmain()
機能するが、 using を使用した同様の呼び出しstdout
が失敗する可能性はどのようにあるのでしょうか?
解決
stdout
in が inとmain()
同じでない場合は可能です。stdout
luaB_print()
しかし、どちらもグローバル変数であり、リンカはそれらを同じにするはずですよね?
まあ、必ずしもそうではありません。グローバル変数stdout
は、C ランタイム ライブラリの一部です。Lua コアがプログラムとは異なる C ランタイム DLL にリンクされている場合、Lua コアとプログラムが実際にはという名前の異なる変数を参照している可能性がありますstdout
。
Dependency Walkerで簡単に確認すると、テスト実行可能ファイルは MSVCRT.DLL (MinGW が推奨する C ランタイム)lua5.1.dll
に対してリンクされていますが、Lua for Windows は MSVCR80.DLL (Visual Studio 2005 の C ランタイム) に対してリンクされています。
この問題は簡単に解決できます。MSVCRT.DLL にリンクされた Lua のビルドにリンクするようにテスト ケースを変更したところ、元のコードが意図したとおりに動作するようになりました。lua5_1-4_Win32_dll6_lib
新しいビルド手順は次のとおりです。現在 BAT ファイルに含まれており、正しくビルドされた Lua コアが含まれていると仮定しています。
setlocal
set LUADIR="lua5_1_4_Win32_dll6_lib"
gcc -o q15787892 q15787892.c -mwindows -I"%LUADIR%\include" "%LUADIR%\lua5.1.dll"
if not exist lua5.1.dll copy %LUADIR%\lua5.1.dll .