2012-09-16 153 views
7

我正在C中實現簡單的庫列表,並且我在編寫find函數時遇到了問題。如何寫任何類型的接受(一個)參數的C函數

我想我的函數接受任何類型的參數來尋找,既: find(my_list, 3)find(my_list, my_int_var_to_find)我已經有信息什麼是列表的元素類型

現在我已經找到了幾個處理這個方式:

  • 不同的功能,後綴爲不同的類型:int findi(void* list, int i)int findd(void* list, double d) - 但我不喜歡這種方法,它看起來像冗餘我和一個API很混亂。

  • 使用UNION:

    typedef union { 
        int i; 
        double d; 
        char c; 
        ... 
    } any_type; 
    

    但這種方式我強迫用戶都知道any_type工會,以及find調用之前創建它。我想避免這種情況。

  • 使用可變參數函數:int find(void* list, ...)。我喜歡這種方法。不過,我擔心的是參數數量沒有限制。用戶可以自由寫int x = find(list, 1, 2.0, 'c'),但我不知道它應該是什麼意思。

我所看到的也回答了這個問題:C : send different structures for one function argument但它是無關緊要的,因爲我想接受非指針參數。

處理此功能的正確方法是什麼?

+0

沒有一個。 – Mehrdad

+2

我會做的方法#1和利用新的C11'_Generic'的宏來區分類型。 – oldrinb

回答

7

你可以而是試圖實現一個類似於像bsearch一個泛型函數,它可以將任何數據類型的磁盤陣列上執行二進制搜索的功能:

void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, 
       int (*compar)(const void *, const void *)) 

而不是硬編碼的不同實現不同你的函數內部的數據類型,而是傳遞一個指向函數的指針,該函數將執行依賴於類型的操作,只有它知道底層的實現。在你的情況下,這可能是某種遍歷/迭代功能。

bsearch需要知道的另一件事(除了明顯的搜索關鍵字和數組長度)是數組中每個元素的大小,以便它可以計算數組中每個元素的地址並將其傳遞給比較功能。


如果您的操作類型有限,那麼擁有一組findX()函數沒有任何問題。上述方法需要將每種數據類型的功能傳遞給bsearch函數,但其​​中一個主要區別是不需要重複常用功能,並且通用函數可用於任何數據類型。

我真的不會說有任何正確的方法來做到這一點,這取決於你,並且真正取決於你想解決的問題。

+0

看起來真的很簡單(一見鍾情)。現在我有有限的類型列表。但如果我想添加另一個類型,我需要編寫另一個包裝函數。我不認爲這是如何解決這個問題的最好方法。 –

+0

@BartekChaber:是的,與C++和Java之類的語言中的模板不同,這並不是一種很好的方式來完成你想要的C語言。製作泛型函數並傳遞函數指針是我通常在項目中進行的。 – AusCBloke

+0

@AusCBloke:取決於你的要求,如果C11沒問題,那就是_Generic。 – kyrias

1

我不確定回答我自己的問題是否禮貌,但我想要您的意見。

我試着用va_list解決這個問題。爲什麼這樣?因爲這樣我可以只寫一個函數。請記住我知道什麼類型的論點應該是。這樣我可以做到這一點:

int find(void* list, ...) { 
     any_type object = {0}; 
     int i = -1; 
     va_list args; 
     va_start(args, list); 
     switch(type_of_elem(list)) { 
     case INT: object.i = va_arg(args, int); break; 
     ... 
     } 
     /* now &object is pointer to memory ready for comparision 
     * f.eg. using memcmp */ 
     return i; 
    } 

這個方案的好處是,我可以換呈現的switch-case,並與其他功能的重用。

在對我關於參數數量沒有限制的擔心稍加研究後,我意識到printf也缺少這個限制。你可以寫printf("%d", 1, 2, 3)。 但我調整我額外的宏解決方案:

#define find_(list, object) find((list), (object)) 

這在編譯時產生錯誤信息,說是find_ macro expects 2 arguments not 3

您對此有何看法?你認爲這是比以前建議的更好的解決方案嗎?

+1

我肯定會用va_list方法。我不確定宏是否增加了很多。最可能的問題是,當列表是雙打時,有人會「查找(列出,12)」。在這種情況下宏仍然沒有給出警告。爲什麼有人會試圖做'find(list,1,2.0,'c')'? – asc99c

+0

@ asc99c爲什麼?因爲函數的簽名允許這樣:) 在搜索時,你絕對沒有鍵入安全。我希望這是這種方法的唯一缺點。 –

相關問題