2010-01-26 62 views
3

我是Bitfighter的主要開發人員,並且在將遊戲移植到64位Linux時遇到問題。這應該是一個相對容易和常見的問題,但它已經讓很多人難堪,我一直沒有找到有關它的好消息。va_args和64位

[[該代碼使用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); 
} 
+0

請問您是否可以添加指示哪條線路發生錯誤的信息?在UserInterface :: drawCenteredString裏面還是在dVsprintf裏面?另外,請添加,什麼編譯器(確切版本)和你使用什麼操作系統(哪個Linux)。 – 2010-01-26 10:10:41

+0

我修改了這個問題,以澄清定義dVsprintf()時發生的錯誤。 – Watusimoto 2010-01-26 23:10:07

+0

在某些64位實現中'va_list'不僅僅是指向堆棧的指針,就像通常的x86 C調用約定一樣。這是因爲前幾個參數是通過寄存器傳遞的。 – 2010-02-11 06:33:45

回答

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) 

,它應該沒有科協工作。

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

首先,你的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實現,並且在系統頭文件中沒有定義,就我所見。

+0

是的,它顯然是!這是我試圖簡化問題的結果,並刪除了無關的代碼。它永遠不會真正遞歸! :-) – Watusimoto 2010-01-26 10:54:55

+0

我不直接調用vsnprintf,因爲我在Windows上使用的是稍微不同的實現,在我的生產代碼中,dVsprintf函數有一個#ifdef,它爲每個平臺使用不同的函數。也就是說,我可能會將dVsprintf變成宏並避免額外的函數調用。 – Watusimoto 2010-01-26 22:58:11

0

在我的情況下,將stdarg.h重命名爲... osprey/obj/include,以fix_starg.h,soved發佈,當然需要stdarg.h的頭文件也需要編輯爲:#包括。顯然stdarg.h坐在外面...... kernel/obj/include正在創建一個仿生衝突。我注意到這個問題有幾個頭文件(特別是types.h和類似的變體)。這些頭文件在內核/包含和仿生中似乎很好,但只要在kernel/obj/incudes或kernel/obj/includes/linux中,似乎會產生問題。我猜這個文件夾的處理方式不同,至少它似乎在仿生中造成了破壞。重命名頭文件似乎解決了這個問題。