Pseudogenerika in C

Lesezeit: 3 Minuten

Benutzeravatar von fb55
fb55

Ich muss einige Methoden implementieren, die mit verschiedenen Arten von Zahlenarrays arbeiten. Normalerweise würde ich für diesen Job Generics verwenden, aber da C sie nicht bereitstellt, versuche ich jetzt, sie mit Makros zu emulieren.

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

#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 kompiliert. Die Clang-Fehlermeldung:

Fehler: erwartet ‘;’ nach Deklarator der obersten Ebene

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

  • Wenn Sie etwas mehr über “Vorlagen”/”Generika” in C lesen möchten, können Sie diese Frage lesen. Es gibt einige interessante Antworten 🙂

    – Jehan

    13. Mai 2013 um 13:33 Uhr

Benutzeravatar von Paul R
Paul R

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 dann #include es in einer Quelldatei für jeden erforderlichen Typ, 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 über den Präprozessor ausführen:

$ 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;
}

  • Funktioniert das auch mit Strukturdefinitionen?

    – Rafaelplayerxd YT

    6. August um 17:42 Uhr

  • @RafaelplayerxdYT: Es hängt davon ab, was Sie mit Ihren verschiedenen Strukturtypen erreichen möchten?

    – PaulR

    7. August um 7:40 Uhr

Jehans Benutzeravatar
Jehan

Eigentlich ist das Beste, was Sie tun können, ein Makro zu definieren, das die Funktion für den angegebenen Typ generiert.

#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 dieses Makro aufrufen, um die benötigten Spezialisierungen zu definieren (mit der C++-Vorlage wird eine ähnliche Sache automatisch vom Compiler durchgeführt).

define_get_minimum(int)
define_get_minimum(double)
define_get_minimum(float)

Eine andere Sache, die ein C++-Compiler automatisch macht, ist die Ableitung der benötigten überladenen Funktion. Das ist in C nicht möglich, also müssen Sie angeben, dass Sie die it-Spezialisierung verwenden. Mit dem folgenden Makro (der C++ <> werden nur durch ersetzt ()):

#define get_minimum(T) get_minimum_##T

Dann sollten Sie es wie folgt aufrufen können:

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

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

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

    – fb55

    14. Mai 2013 um 9:47 Uhr

  • @ fb55 Nun, generisch und nicht groß sind in C nicht so kompatibel 🙂

    – Jehan

    14. Mai 2013 um 16:24 Uhr

  • Das hat mir an der Antwort von @PaulR gefallen: Das Makro war ziemlich kurz und an anderen Stellen wiederverwendbar 🙂

    – fb55

    14. Mai 2013 um 16:27 Uhr

  • @ fb55 Das Problem ist, dass es von einem Parameter zur Kompilierzeit abhängt. Mit seiner Version kann man das nicht verwenden float und die int Version der Funktion in derselben Compile-Unit :/

    – Jehan

    14. Mai 2013 um 16:29 Uhr

  • Ich habe meine Antwort jetzt aktualisiert, um zu zeigen, wie mehrere Funktionen für alle erforderlichen Typen in einer Übersetzungseinheit generiert werden.

    – PaulR

    14. Mai 2013 um 18:00 Uhr

Sie können außer einer Schalteranweisung auch Funktionszeiger (Array von Funktionszeigern) verwenden und das Argument des Schalters als Index an das Array übergeben.

1392070cookie-checkPseudogenerika in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy