2012-03-26 110 views
1

我用G ++編寫64位操作系統的cdecl,和我有一個可變參數函數,如:如何迫使可變參數函數

void DbgPrint(const char *fmt, ...); 

其行爲應該挺喜歡的printf。 這裏的問題是g ++遵循System V ABI,因此它傳遞RDI,RSI,RDX,RCX,R8,R9中的第一個參數,然後將剩餘的(如果有的話)壓入堆棧。

將舊的stdarg.h宏va_start,va_arg等與cdecl一起使用,非常簡單,因爲va_arg只是將下一個元素放在堆棧中。但是現在這些宏直到第七個參數纔會工作。

唯一不可能性的解決方案是(IMHO):

  • 強制克++創建一個的cdecl功能。這似乎是不可能的,因爲__ 屬性 __((cdecl))被故意明確突出顯示爲忽略
  • 有一組新的宏,這些宏使用傳遞參數的新方法。

(我實際上在Win上工作,所以我沒有glibc頭文件來檢查它們的實現)。

任何人都有解決方案嗎?提前致謝。

回答

2

stdarg.h不是libc的一部分,它是編譯器本身的一部分。所以如果你使用的是g ++,它應該有一個stdarg.h來處理它 - 它通常被安裝在gcc的私有包含目錄中,該目錄在系統包含之前被自動搜索。

如果您在GCC的STDARG.H看,你看到va_宏都被定義映射到__builtin編譯器神奇知道如何處理功能:

typedef __builtin_va_list __gnuc_va_list; 
typedef __gnuc_va_list va_list; 

#define va_start(v,l) __builtin_va_start(v,l) 
#define va_end(v) __builtin_va_end(v) 
#define va_arg(v,l) __builtin_va_arg(v,l) 

和那些建宏都明白調用目標ABI使用的約定。

+0

另請注意,即使在x86(32位)上,用於實現'stdarg.h' **的舊方法(僞指針算術)在現代GCC版本上不起作用。在編譯器選擇內聯函數的情況下,參數在堆棧中根本不存在,即使不是,也有其他方式可以被破壞。不幸的是'__builtin'函數真的很有必要。 – 2012-03-26 17:40:07

+0

謝謝你,你一直很有用:) – 2012-03-26 17:48:44