2013-05-13 14 views
24

Ich muss einige Methoden implementieren, die mit verschiedenen Arten von Anzahl Arrays stopfen. Normalerweise verwende ich Generics für diesen Job, aber da C sie nicht bereitstellt, versuche ich jetzt, sie mit Makros zu emulieren.Pseudo-Generika in C

Hier ist ein Beispiel dafür, was ich versuche zu tun:

#ifndef TYPE 
#define TYPE int 
#endif 

TYPE get_minimum_##TYPE (TYPE * nums, int len){ 
    TYPE min = nums[0]; 

    for (int i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

Dies wird jedoch nicht kompilieren. Die Clam-Fehlermeldung:

error: expected ';' after top level declarator

Gibt es eine Möglichkeit, dies in C zu tun? Oder muss ich das für jeden Typ von Hand umsetzen?

+0

fyi generics in C# und java sind eine Laufzeiteinrichtung. –

+0

Wenn Sie ein wenig mehr über "Templates"/"Generics" in C lesen möchten, [können Sie diese Frage lesen] (http://stackoverflow.com/questions/10950828/simulation-of-templates-in-c). Es gibt einige interessante Antworten :) – Jehan

Antwort

25

Sie können in einer Header-Datei so etwas tun:

// 
// generic.h 
// 

#define TOKENPASTE(x, y) x ## y 

#define GET_MINIMUM(T) TOKENPASTE(get_minimum_, T) 

TYPE GET_MINIMUM (TYPE) (TYPE * nums, size_t len){ 
    TYPE min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

und #include es dann in einer Quelldatei für jede gewünschte Art, zB:

// 
// generic.c 
// 

#define TYPE int 
#include "generic.h" 
#undef TYPE 

#define TYPE float 
#include "generic.h" 
#undef TYPE 

Sie können dies testen, indem Sie es durch den Präprozessor:

$ gcc -E generic.c 

int get_minimum_int (int * nums, size_t len){ 
    int min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

float get_minimum_float (float * nums, size_t len){ 
    float min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 
23

Eigentlich ist das Beste, was Sie tun können, ist zu definieren Acro, die die Funktion für den angegebenen Typ generieren wird.

#define define_get_minimum(T) \ 
T get_minimum_##T(T* nums, int len){ \ 
    T min = nums[0]; \ 
    for (int i = 1; i < len; i++) { \ 
     if (nums[i] < min) { \ 
      min = nums[i]; \ 
     } \ 
    } \ 
    return min; \ 
} 

Dann können Sie das Makro aufrufen, um die Spezialisierungen zu definieren, die Sie benötigen (mit C++ Vorlage wird eine ähnliche Sache automatisch vom Compiler getan).

Eine andere Sache, die ein C++ - Compiler automatisch macht, ist die überladene Funktion, die Sie benötigen. Sie können das nicht in C haben, also müssen Sie sagen, dass Sie die it-Spezialisierung verwenden.

#define get_minimum(T) get_minimum_##T 

Dann sollten Sie in der Lage sein, es die folgende Art und Weise zu nennen: Sie können mit dem folgende Makro (das C++ <> durch () nur ersetzt) ​​eine Vorlage-ähnliche Syntax für die Funktion simulieren

int main() 
{ 
    // Define arr as char* array... 
    // Do stuff... 
    int res = get_minimum(int)(arr, 3); 
} 

Ich habe diesen Code nicht getestet, aber es sollte funktionieren.

+0

+1: Ich habe es gerade getestet und es scheint zu funktionieren. –

+0

Ich mag den Stil des letzten Anrufs, aber ich habe versucht, dies ohne große Makros zu archivieren. – fb55

+0

@ fb55 Nun, generische und nicht große sind nicht so kompatibel in C :) – Jehan

0

Sie können auch Funktionszeiger (Array von Funktionszeigern) verwenden, die keine switch-Anweisung sind, und das Argument des Schalters als Index an das Array übergeben.