va_args和64位

时间:2010-01-26 09:15:28

标签: c++ linux 64-bit printf

我是Bitfighter的首席开发者,并且在将游戏移植到64位Linux时遇到了问题。这应该是一个相对容易和常见的问题,但它已经困扰了许多人,我找不到有关它的好信息。

[[代码用gcc版本4.1.2和其他代码编译32位,并且有64位Linux的几种变体失败,但我依赖其他人的报告,并且没有确切版本的失败的gcc。但对于一些Linux版本来说,它失败了。我99%肯定这不是编译器版本问题。 ]

我有以下内容:

 void UserInterface::drawCenteredString(int y, int size, const char *format, ...)
   {
    va_list args; 
    va_start(args, format); 
    char buffer[2048]; 
    dVsprintf(buffer, sizeof(buffer), format, args); 
    va_end(args);

    drawCenteredString2(y, size, buffer);
 }   

 // Elsewhere, in platform.cpp... (this is where the error occurs)

 S32 dVsprintf(char *buffer, int bufferSize, const char *format, void *arglist)
 {
    return vsnprintf(buffer, bufferSize, format, (char *) arglist);
 }

这在32位平台上运行良好。但是,当我在64位Linux上编译它时,它失败了:

 platform.cpp:457: error: cannot convert 'char*' to '__va_list_tag*' for argument '4' to 'int TNL::vsnprintf(char*, size_t, const char*, __va_list_tag*)'

我尝试了很多变体,包括:

return vsnprintf(buffer, bufferSize, format, (va_list) arglist);

没有成功。

有没有人对如何使这个构造变得可移植有任何想法,或者使用更多64位友好机制实现相同目的?

而且,对于奖励积分:-)谁能告诉我va_list_tag thingy来自哪里?

谢谢!

============================================

以下是我们解决的解决方案,使用了另一个例子:

logprintf("Hello %s", name);

呼叫

void logprintf(const char *format, ...)
{
   va_list s;    
   va_start( s, format );

   logger(LogConsumer::GeneralFilter, format, s);
   va_end(s);
}

呼叫

void logger(LogConsumer::FilterType filtertype, const char *format, va_list args)
{
   char buffer[4096];

   vsnprintf(buffer, sizeof(buffer), format, args);

   Platform::outputDebugString(buffer);
}

4 个答案:

答案 0 :(得分:5)

更改

S32 dVsprintf(char *buffer, int bufferSize, const char *format, void *arglist)

S32 dVsprintf(char *buffer, size_t bufferSize, const char *format, va_list arglist)

并且它应该在没有演员的情况下工作。

答案 1 :(得分:3)

首先,dVsprintf的原型是错误的。

S32 dVsprintf(char *buffer, int bufferSize, const char *format, void *arglist)

arglist显然具有来自上下文的类型va_list

其次,为什么不使用vsnprintf而不是调用dVsprintf

第三,你的函数drawCenteredString显然无限地递归,这是不好的:

void UserInterface::drawCenteredString(int y, int size, const char *format, ...)
{
    ///...
    drawCenteredString(y, size, buffer);
}   

__va_list_tag*必须是va_list的基础类型。这很难验证,因为va_list是gcc实现依赖的,并且在我看到的系统头文件中没有定义。

答案 2 :(得分:2)

这应该有效:

S32 dVsprintf(char *buffer, int bufferSize, const char *format, ...)
{
    va_list va_args;
    va_start( va_args, format );
    S32 result = vsnprintf(buffer, bufferSize, format, va_args); 
    va_end( va_args );
    return result;
}

__va_list_tag*...的隐藏实现类型,这就是为什么它不喜欢char*类型转换 - 突然指针不再是32位...

考虑到这是C ++,您是否考虑过比va_args更多的C ++方法?想到了几个想法:

答案 3 :(得分:0)

在我的情况下,重命名stdarg.h在... osprey / obj / include,到fix_starg.h,soved发布,当然需要stdarg.h的标题也需要编辑为:#include 。显然stdarg.h坐在外面...... kernel / obj / include正在创建一个仿生冲突。我已经注意到这个问题有几个头文件(特别是types.h和类似的变体)。内核/包含和仿生中的标题似乎很好但是只要在kernel / obj / incudes或kernel / obj / includes / linux中,它似乎就会产生问题。我猜这个文件夹的处理方式不同,至少它似乎在仿生中造成了破坏。重命名头文件似乎解决了这个问题。