2012-10-06 32 views
3

我在C新手..我在想,如果我有三個數組是這樣的:是否可以實現一個可以打印C中任何類型數組的函數?

int a[] = {1, 2, 3} 
char b[] = {'a', 'c', 'k'} 
float c[] = {4.5, 5.8} 

是否可以寫一個多態函數,可以打印這些陣列像這樣的任何一個?

prarray(a); prarray(b); prarray(c); 

這種形式也是可以接受的:

prarray(a, int); prarray(b, char); prarray(c, float) 

是否有可能制定出功能void prarray(void *)?有沒有人有任何想法?

+2

C中的多態性!!!!!!!!!!!!!從什麼時候開始? – perilbrain

+1

@perilbrain我知道C沒有內置的多態。有沒有其他一些方法來模仿多態?像'void *' –

+1

C是一種原始語言,它適合編寫內核或作爲輸出語言,但很少。如果你想這樣做,有幾十種其他語言是可能的。 –

回答

3

您將無法做到這一點無需提供大量的援助,以調用函數,以便它可以完成自己的工作。看看標準C庫中的兩個'多態'功能,qsort()bsearch()

void qsort(void *base, size_t nel, size_t width, 
     int (*compar)(const void *, const void *)); 
void *bsearch(const void *key, const void *base, size_t nel, 
     size_t width, int (*compar)(const void *, const void *)); 

printf()scanf()家庭是處理多種類型的其他功能。

您的打印陣列功能可能會需要:

typedef int (*DataPrinter)(void *ctxt, void *data); 
extern int prarray(void *base, size_t nel, size_t width, 
        DataPrinter pr_func, void *ctxt) 

數據打印功能指針將負責打印一張價值 - 由data參數指定。 ctxt值是指向數據打印機功能所需的任何控制信息的指針(它可能與FILE *一樣簡單,可能更復雜)。從數據打印機功能返回的值是寫入的字符數;從prarray()返回的值是寫入的字符總數。

這當然只適用於一維數組。爲了打印2D或3D陣列的小部分,您需要更復雜的代碼。如果您需要擔心換行等問題,那很可能是ctxt的域名。或者你爲這個功能設計更復雜的接口。請注意,爲指定值分隔符提供的唯一機制是通過ctxt結構。這將起作用(或可以開展工作),但可能太笨拙。


_Generic的C2011溶液是有趣的,但需要用於N種類型的N個函數,其中每個把手印刷的陣列。我無法完全擺脫:我的解決方案需要N + 1個函數,但其​​中只有一個(1)處理數組; N個函數每個處理打印給定類型的單個值,這比打印整個給定類型的數組更簡單。當然,如上所述,它需要在每個相關平臺上使用C 2011編譯器。由於至少有一個「經常相關」的平臺沒有供應商提供的C 1999編譯器,因此可能需要一段時間才能在該平臺上使用C 2011。

0

在c中沒有多態性。要做到這一點沒有不安全的做法,必須有三個不同的功能通過陣列及其長度。即; void print_ints(int * a,int size);等等。

+0

uhm,請查看C11 –

+0

@ Cheersandhth.-Alf:您是否想知道C11中您認爲適用於此問題的功能? –

+0

@JonathanLeffler:http://stackoverflow.com/a/12755633/464581 –

0

簡短的回答是沒有。

較長的答案是,你可以創建包含不同類型的值,然後寫一個知道如何將它們打印出功能的新的數據類型。這會給你你想要的,但是定義你的值可能在語法上很尷尬。

坦率地說,正是這樣的問題,這鼓勵人們去創造動態語言,面向對象等。

我的C是真的生疏,但...

struct varyThing { 
    char typeCode; // indicates what type of data it is. 
    union valueUnion { 
     long longValue; 
     float floatValue; 
     char string[32]; 
    } value; 
}; 

整體結構僅佔用34個字節,具體取決於類型大小和字節對齊以及其他編譯器細節。

6

最新的C標準是C11(C 2011)。

它提供了關鍵字_Generic(§6.5.1.1通用選擇,在§6.5表達式下)做你想要的東西。

例如,

#define prarray(A, len) _Generic((A), \ 
    int: prarray_int, \ 
    char: prarray_char, \ 
    float: prarray_float, \ 
    )(A, len) 

void prarray_int(int* a, ptrdiff_t len) { ... } 
void prarray_char(char* a, ptrdiff_t len) { ... } 
void prarray_float(float* a, ptrdiff_t len) { ... } 

現在,所有你需要做的,是得到了C11編譯器的持有! :-)

或者做C11宏的工作,多一點手動 - 實際上,將類型的名稱作爲顯式宏參數傳遞,然後使用##令牌粘貼來生成函數名稱。免責聲明:未經測試的代碼(我沒有C11編譯器),以及我自1990年代後期以來沒有使用過C語言。

2

我對同一問題的第二個答案。

你當然可以創建一個函數,如果你傳遞它的類型信息,它會知道該如何處理數據。所以,你可以使用一個調用約定:

prarray(a, len, 'i'); prarray(b, len, 'c'); prarray(c, len, 'f'); 

這將是更好地使用「我」,「C」和「F」,但你的總體思路常數。功能定義如下:

void parray(void *genericPtr, int len, char typeCode) { 
    if (typeCode == 'i') { 
     int *intArray = (int*) genericPtr; 
     printIntArray(intArray, len); 
    } 
    if (typeCode == 'c') { 
     char *charArray = (char*) genericPtr; 
     printString(charArray, len); 
    } 
    if (typeCode == 'f') { 
     float *floatArray = (float*) genericPtr; 
     printFloatArray(floatArray, len); 
    } 
} 

注意邪惡的,不安全的類型轉換。

+0

你將需要傳遞一個長度。 –

+0

編輯,謝謝。你知道,可能是C中多態行爲的最好例子,我見過它在OpenSSL庫中。 – slashingweapon

1

你可以得到無C11編譯器最接近的可能是一個宏觀

#define prarray(array, format, length) ({\ 
    size_t i;\ 
    size_t _length = length ; 
    for (i = 0; i < _length; i++) \ 
     printf(format ",", (array)[i]);\ 
})\ 

調用與格式爲您的格式化字符串。例如"%c" for character,"%d" for int etc ...

+0

我想你會想要「%c」爲char,「%d」爲int等等...... – slashingweapon

+0

是的,你是對的 –

相關問題