2010-10-27 29 views
2

我的圖書館提供了一個回調點,我的圖書館用戶可以註冊以獲取信息。回調的一般形式是int,後面跟着各種類型取決於int值的參數。因此,我定義了回調類型和函數來設置它如下。什麼是C回調函數的參數更好:va_list或省略號?

typedef void (* callback_func_t)(int type, ...); 
void set_callback_func(callback_func_t callback); 

在我的庫中,我一直在調用這個函數,作爲用戶設置函數,或者我提供的默認函數。有用。

現在,我想添加一個間接級別,以便能夠調用多個註冊的回調。麻煩的是我的內部回調函數仍然需要省略號參數,也必須用省略號調用回調函數。因此,我的內部函數必須解釋type,從va_list中解壓參數並將它們作爲callbacj函數的參數。

void internal_callback(int type, ...) { 
    va_list args; 
    va_start(args, type); 
    switch (type) { 
    case 0: call_callback(type, va_arg(args, int)); break; 
    // ... 
    } 
    va_end(args); 
} 

但隨後,在用戶執行回調,也會有同樣的va_list使用以及的參數解釋,根據type值。解決方案是直接將va_list作爲參數傳遞給回調函數,使內部回調函數的實現變得明顯。

typedef void (* callback_func_t)(int type, va_list args); 

我的問題是:這是很好的做法,定義一個回調函數類型採用va_list作爲參數?我可以像上面那樣定義我的回調函數類型,但是與頂部定義相比有什麼優點和缺點?

回答

3

我假設有一個有限的已知數量的類型?如果是這樣,爲什麼不使用枚舉和工會類型安全的一定程度上,這會順帶還解決您的問題:

enum callback_arg_type { INT_ARG, DOUBLE_ARG, VECTOR_ARG }; 

union callback_arg 
{ 
    int as_int; 
    double as_double; 
    struct { double x, y, z; } as_vector; 
}; 

typedef void (*callback_func_t)(
    enum callback_arg_type type, union callback_arg arg); 

根據參數大小的差異,這可能是一個好主意,通過一個指針代替。你也可以提供一些宏來提供回調調用一個更好的語法,但如果他們只會被調用從資料庫中,它可能不值得:

union callback_arg arg = { .as_int = 42 }; 
callback_fn(INT_ARG, arg); 

是對自己很短。

2

我會去與va_list版本。用戶已經在處理va_list的處理問題了,所以你不要通過隱藏它來保存任何內容。

此外使用列表而不是嘗試重新參數將減少堆棧使用。如果必須將參數重新提交到它們的函數中,它將創建所有這些參數的新副本,但傳遞va_list類型將只使用已經在堆棧上的那些參數的實例。最後,你的代碼會更簡單(如果我正確地理解了這個問題),並且你將保存每個用戶不必調用va_startva_end(這可能不會改變其功能中的輸出代碼大多數實現方式爲stdarg),但除此之外,他們都必須鍵入這些呼叫,並且(取決於如何在平臺上實施stdarg),他們需要確保在返回之前確實實際撥打va_end(如果返回時很容易錯過一個錯誤)。

相關問題