2012-10-27 72 views
2

因此,我一直在爲腳本語言製作一個自定義語法分析器,並希望只能傳遞省略參數。我不需要或者不需要初始變量,但是微軟和C似乎想要其他的東西。僅供參考,請參閱下方的信息。無初始參數而獲得省略號功能參數

我已經看過了va_ *定義

#define _crt_va_start(ap,v) (ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)) 
#define _crt_va_arg(ap,t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) 
#define _crt_va_end(ap)  (ap = (va_list)0) 

,我不想要的部分,在va_start中的訴作爲一個小背景我可以勝任,我知道堆棧是如何工作的,所以我知道這裏發生了什麼。我想知道是否有一種方法可以在不使用內聯彙編的情況下獲取函數堆棧庫。

想法我有:

#define im_va_start(ap) (__asm { mov [ap], ebp }) 

等..但實際上我認爲這是個混亂的,我做錯了。

struct function_table { 
    const char* fname; 
    (void)(*fptr)(...); 
    unsigned char maxArgs; 
}; 
function_table mytable[] = { 
{ "MessageBox", &tMessageBoxA, 4 } }; 

...一些功能整理着一個const char *傳遞給它找到MyTable的匹配功能,並與PARAMS調用tMessageBoxA。此外,maxArgs參數正好可以檢查是否正在發送有效數量的參數。我有個人理由不希望將其發送到函數中,但同時我們可以說這是因爲我很好奇。

這只是一個例子;自定義庫是我將要實現的,所以它不會只是調用WinAPI的東西。

void tMessageBoxA(...) { 
// stuff to load args passed 
MessageBoxA(arg1, arg2, arg3, arg4); 
} 

我使用的是__cdecl調用約定和我擡頭可靠方式獲得一個指向堆棧(不是頂部)的基礎,但我似乎無法找到任何。另外,我並不擔心函數安全性或類型檢查。


編輯:感謝您的輸入,它似乎是不可能的。

我的修補程序已結束了

#define im_va_start(ap) {\ 
     __asm push eax\ 
     __asm mov eax, ebp\ 
     __asm add eax, 8h\ 
     __asm mov ap, eax\ 
     __asm pop eax\ 
    } 

,然後我可以繼續正常。至於爲什麼我需要它,我正在做一些(獨特的)閱讀:不安全的技巧,並使用一個結構數組和一個指向上面定義的函數的指針。由於每個功能都是獨一無二的,而且大部分都來自我的自定義庫,它們有不同的行爲。我真的不知道如何解釋它,但是當我完成POC時我會發布源代碼。

我並不真的擔心可移植性,所以必須要工作。另外,爲了計算我所做的參數:

#define im_va_count(ap, num, t) {\ 
for(num = 0; *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) > 0; ++num){ }\ 
--num;\ 
im_va_start(argptr);\ 
} 

這對我有用。如果任何人的興趣......

+0

我必須問,你有沒有找過可變模板?順便提一下,這是一個很好的問題。 –

+0

如果函數對傳遞給它的參數一無所知,你的函數將如何執行任何操作? –

+0

在他的程序中,他顯然有一些邏輯可以做到這一點,但這位提問者並沒有顯得無足輕重,從而沒有想到這樣簡單的事情。 –

回答

2

可惜這是不可能的,C標準說:

函數可以用不同類型的參數個數可變調用。由於6.9.1中描述的 ,其參數列表包含一個或多個參數。

...不算作「一個或多個參數」。此外,

在訪問未命名參數之前應調用va_start宏。

即它應該被稱爲像

va_start(va_list, parmN) 

參數parmN是最右邊的參數的函數定義的變量 參數列表中的識別符(該一個就在, ...之前)。

所以,正如你所看到的,在標準C++省略號之前,你不能有一個沒有至少一個參數的可變參數函數。非便攜式裝配技巧是最接近你可以來。