2013-04-03 78 views
0

我的代碼看起來像這樣(Windows平臺):嵌入式Lua中沒有打印到控制檯分配

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)); 
} 

我不能讓Lua的輸出,同時(也被打印的Lua錯誤)正常的printf作品

+0

那些錯誤是什麼? – hjpotter92

+0

@ hjpotter92例如,如果不是打印我寫foo – user206334

回答

4

TL; DR:該程序使用多個版本的C運行時庫。不要這樣做。它總是會導致來自其他正確代碼的神祕症狀。

背景

在它的面前,你的代碼現在應該工作。而且,如果在這裏建立並保持聯繫,我可以使其工作。作爲參考,我正在使用MingW GCC 4.7.2,用於Win7 Pro上的32位Windows。但我相信任何針對Windows的編譯器都會出現潛在的問題。

我將通過查找這個錯誤的過程,希望看看我是如何計算出來的。但如果你不耐煩,跳到最後,然後回到這裏看看我是如何到達那裏的。

測試的代碼

首先,我裹在足夠的鍋爐板代碼片段,使其編譯並運行在所有:與GCC

#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 
} 

編譯

我編譯和鏈接有關的儘可能簡單的在Windows上,這是不是太糟糕,因爲我有一個安裝的Windows的Lua的副本,這恰好使環境變量LUA_DEV指向它的安裝:

gcc -o q15787892 q15787892.c -mwindows -I"%LUA_DEV%\include" "%LUA_DEV%\lua5.1.dll" 

-mwindows標誌告訴GCC(特別是鏈接器ld)將可執行文件標記爲完整的Windows GUI程序。如果沒有這個標誌,你會得到一個控制檯程序,該控制檯程序已經分配了一個控制檯,而AllocConsole()將僅僅爲持有該命令提示符的控制檯提供句柄。

結果

有趣的是,既沒有呼叫print()也不io.write()產生的輸出。我在Lua文本中引入了語法錯誤,並注意到它輸出到控制檯,顯示stdout確實被正確重定向。

我調用freopen()和之後printf("%p %p %p", fp, stdout, oldstdout);前加入FILE *old=stdout;。所有三個指標完全相等,表明freopen()沒有做一些不尋常的事情。

在Lua 5.1的print()函數中查找源代碼,我們發現它只是簡單地調用fputs(s,stdout)

那麼如何從main()調用printf()工作,但使用stdout的類似調用失敗?

解決方案

這是可能的,如果stdoutmain()是不一樣的,如luaB_print()stdout

但都是全局變量,鏈接器應該使它們是相同的,對吧?

好吧,不一定。全局變量stdout是C運行時庫的一部分。如果Lua內核鏈接到與程序不同的C運行時DLL,則有可能Lua內核和程序實際上是指名爲stdout不同的變量。

快速檢查與Dependency Walker表明,我的測試可執行文件對MSVCRT.DLL(由MinGW的首選C運行時)鏈接,但lua5.1.dll從Lua適用於Windows的對抗MSVCR80.DLL鏈接(從Visual Studio 2005的C運行時)。

此問題很容易解決。我將測試用例更改爲鏈接到針對MSVCRT.DLL鏈接的Lua構建,現在原始代碼按預期工作。這裏是新的建設步驟,現在在一個BAT文件中找到,並假設lua5_1-4_Win32_dll6_lib包含正確內置的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 . 
+0

驚人的調查!我能說些什麼......我知道一定不能混合運行時,我認爲我從lua網站上得到了正確的dll。無論如何,我無法想象,不同的運行時間會引入這樣的結果,並一直認爲它會引入更糟糕的和程序崩潰的錯誤。 – user206334

+0

@ user206334,它*會產生更糟糕的錯誤。你有「幸運」,只是有一個謎。這是因爲你的代碼在表面上是正確的,所以我決定寫一個更長的答案來說明出了什麼問題。盯着正確的代碼尋找問題通常會導致一種隧道視覺。這似乎是從不同的角度展示如何看待它可能對您和其他人有所幫助。 – RBerteig

0

另一個可能的原因是,luaxx.dll被釋放,並且測試項目debuged版本。因此,luaxx.dll使用msvcrxx.dll,但測試項目使用msvcrxxd.dll - 微軟c運行時版本。