我想知道是否有任何方法將參數動態地傳遞給可變參數函數。即如果我有一個函數動態地將參數傳遞給可變參數函數
int some_function (int a, int b, ...){/*blah*/}
,我接受了一堆數值從用戶,我想這些值傳遞到函數的一些方法:
some_function (a,b, val1,val2,...,valn)
我不想寫所有這些功能的不同版本,但我懷疑沒有其他選擇?
我想知道是否有任何方法將參數動態地傳遞給可變參數函數。即如果我有一個函數動態地將參數傳遞給可變參數函數
int some_function (int a, int b, ...){/*blah*/}
,我接受了一堆數值從用戶,我想這些值傳遞到函數的一些方法:
some_function (a,b, val1,val2,...,valn)
我不想寫所有這些功能的不同版本,但我懷疑沒有其他選擇?
嘗試傳遞一個數組可能會很有趣,然後使用可變參數宏。根據堆棧對齊情況,它可能正常工作(tm)。
這可能不是最佳解決方案,我主要發佈它,因爲我發現這個想法很有趣。 試用後,這種方法在我的Linux x86上工作,但不在x86-64上 - 它可能可以改進。此方法將取決於堆棧對齊,結構對齊和可能更多。
void varprint(int count, ...)
{
va_list ap;
int32_t i;
va_start(ap, count);
while(count--) {
i = va_arg(ap, int32_t);
printf("Argument: %d\n", i);
}
va_end(ap);
}
struct intstack
{
int32_t pos[99];
};
int main(int argc, char** argv)
{
struct intstack *args = malloc(sizeof(struct intstack));
args->pos[0] = 1;
args->pos[1] = 2;
args->pos[2] = 3;
args->pos[3] = 4;
args->pos[4] = 5;
varprint(5, *args);
return 0;
}
變量函數使用調用約定,其中調用者負責從棧中彈出函數參數,所以是的,可以動態執行此操作。它在C中沒有標準化,通常需要一些程序集手動推送所需的參數,並正確調用可變參數函數。
cdecl
調用約定要求參數按正確的順序推送,並且在調用之後,在調用之前作爲參數推送的字節被彈出。通過這種方式,被調用的函數可以接收任意數量的參數,因爲調用者將處理將堆棧指針恢復到它的預調用狀態。 ...
之前的參數佔用的空間是推送的字節數的安全下限。額外的可變參數在運行時被解釋。
FFCALL是一個庫,它提供了將參數動態傳遞給可變參數函數的包裝器。您感興趣的功能組是avcall。這裏有一個例子給你打電話了以上的功能:
#include <avcall.h>
av_alist argList;
int retVal;
av_start_int(argList, some_function, retval);
av_int(argList, a);
av_int(argList, b);
av_type(argList, val1);
...
av_type(argList, valn);
av_call(argList);
您也可能會發現this link討論用C產生繞可變參數函數的包裝,對感興趣的理由,爲什麼這不是標準C.
一個標準的方法是讓每個可變參數函數伴隨着一個va_list
評論對象(如在printf和vprintf中)。該可變參數版本只是將...
轉換爲va_list
(使用來自stdarg.h
的宏),並調用其實際工作的va_list-sister。
謝謝,我會研究這種方法。 – tommobh 2009-11-12 12:06:26
@atzz雖然同樣的問題。我仍然需要動態地將參數添加到該函數,無論它是否調用其va_list-姐妹。你的意思是我將這些值轉換爲va_list,然後使用va_list-taking姐妹函數來代替? – tommobh 2009-11-12 12:54:45
@tommobh - 我想我錯誤地解釋了你的問題。通過閱讀評論,我認爲你有一種獲得不同類型值的方法(例如,來自gui),並且需要將它們傳遞給一個函數;這是對的嗎?在這種情況下,va_list不會有太大的幫助。如果你不想依賴黑客,你將不得不改變功能... – atzz 2009-11-12 16:10:37
取決於你傳遞的是什麼,它可能是你在此之後的一個有區別的聯盟(正如評論中暗示的那樣)。這將避免需要可變參數函數或void*
的數組,並回答「問題如何some_function知道你實際上通過它」。你可能有代碼是這樣的:
enum thing_code { INTEGER, DOUBLE, LONG };
struct thing
{
enum thing_code code;
union
{
int a;
double b;
long c;
};
};
void some_function(size_t n_things, struct thing *things)
{
/* ... for each thing ... */
switch(things[i].code)
{
case INTEGER:
/* ... */
}
}
你可以藉此更進一步,通過與一個或多個指針替換code
該做些什麼,每個thing
有用的功能,避免了開關。例如,如果你想要做的是簡單地打印出每一件事情,你可以有這樣的:
struct thing
{
void (*print)(struct thing*);
union
{
...
};
}
void some_function(size_t n_things, struct thing *things)
{
/* .. for each thing .. */
things[i]->print(things[i]);
/* ... */
}
@Ned:我正在使用的可變參數函數是在一個庫中,我最好不喜歡改變(即我不想要改變'some_function()')。用戶可以輸入他們喜歡的任何類型的數量(在合理範圍內),因此定義嚴格的聯合似乎不會起作用。一系列void *或Anacrolix的建議似乎是我最好的選擇。無論是我還是我寫一些內聯彙編:S。 – tommobh 2009-11-12 13:52:15
但是,如果你不能改變some_function,你怎麼能通過它一個void *數組?用戶在這裏,我們是在討論一個使用你的代碼的開發者,或者是該程序的最終用戶? – Ned 2009-11-12 13:56:34
@Ned:User =最終用戶。是的,我明白你的意思了。我不想改變函數,因爲函數本身調用另一個可變參數函數,我也必須改變它。它只會雪球。我感覺我回到了我開始的地方。 – tommobh 2009-11-12 14:14:16
如果所有值均爲同一類型(如你的問題似乎暗示 - 糾正我,如果我錯了)我建議不要使用可變參數函數,而是傳遞一個數組。看到這裏的一些宏魔法漂亮起來,當你想傳遞固定數量的參數:http://stackoverflow.com/questions/1375474/variable-arity-in-c/1375636#1375636 – Christoph 2009-11-12 11:59:38
不,他們是不同的類型。 – tommobh 2009-11-12 12:01:32
@tommobh:如果你將值包裝在union中,或者將'void *'數組傳遞給值而不是值本身,但數組方法仍然可以工作 – Christoph 2009-11-12 12:04:10