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

我无法获得 Lua 输出,而正常的 printf 工作(也打印 Lua 错误)

4

2 回答 2

4

TL;DR:该程序使用了多个版本的 C 运行时库。不要那样做。它总是会导致其他正确代码的神秘症状。

背景

从表面上看,您提供的代码应该可以工作。而且,如果在这里小心建造和链接,我可以让它工作。作为参考,我在 Win7 Pro 上使用 MingW GCC 4.7.2 构建 32 位 Windows。但我相信任何针对 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"

-mwindows标志告诉 GCC(特别是链接器ld)将可执行文件标记为完整的 Windows GUI 程序。如果没有该标志,您将获得一个已经分配了控制台的控制台程序,并且 AllocConsole() 将简单地为持有命令提示符的程序提供句柄。

结果

有趣的是,既没有调用print()也没有io.write()产生输出。我在 Lua 文本中引入了一个语法错误,并注意到它确实输出到了控制台,表明它stdout确实被正确重定向了。

FILE *old=stdout;在调用之前freopen()printf("%p %p %p", fp, stdout, oldstdout);之后添加了它。所有三个指针完全相等,表明freopen()没有做任何不寻常的事情。

查看 Lua 5.1 函数实现的源代码,print()我们发现它只是调用fputs(s,stdout).

printf()那么,对from的调用怎么可能main()有效,但类似的调用 usingstdout失败?

解决方案

如果stdoutinmain()stdoutin不同,则有可能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 构建,现在原始代码按预期工作。这是新的构建步骤,现在可以在 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 .
于 2013-04-03T18:37:04.483 回答
0

另一个可能的原因是 luaxx.dll 发布了,而测试项目是调试版。所以,luaxx.dll 使用的是 msvcrxx.dll,而测试项目使用的是 msvcrxxd.dll——微软 c 运行时的调试版。

于 2013-10-24T09:17:34.590 回答