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
的類似調用失敗?
解決方案
這是可能的,如果stdout
在main()
是不一樣的,如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 .
那些錯誤是什麼? – hjpotter92
@ hjpotter92例如,如果不是打印我寫foo – user206334