1

私のコードは次のようになります(Windowsプラットフォーム):

AllocConsole();
FILE *fp = freopen("CONOUT$", "w", stdout); //couldn't find documentation what CONOUT$ actually is
lua_State *lua_state = luaL_newstate();
luaL_openlibs(lua_state);
if(luaL_dostring(lua_state, "print 'It works!'"))
{
    printf("%s\n", lua_tostring(lua_state, -1));
}

通常の printf は機能しますが、Lua の出力を取得できません (Lua のエラーも出力されます)。

4

2 に答える 2

4

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 プログラムとしてマークするように-mwindowsGCC (具体的には 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が失敗する可能性はどのようにあるのでしょうか?

解決

stdoutin が inとmain()同じでない場合は可能です。stdoutluaB_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 .
于 2013-04-03T18:37:04.483 に答える
0

別の考えられる理由は、luaxx.dll がリリースされ、テスト プロジェクトがデバッグ バージョンであることです。したがって、luaxx.dll は msvcrxx.dll を使用しますが、テスト プロジェクトは msvcrxxd.dll (Microsoft C ランタイムのデバッグ バージョン) を使用します。

于 2013-10-24T09:17:34.590 に答える