Generische Listen



  • Hallo,

    ich bin gerade dabei generische Listen mit Hilfe des Makroprozessors zu realisieren. Der Code funktioniert soweit, nur ist er noch nicht ganz generisch.

    Wie man in gen.c/h sehen kann muss ich noch jedes Mal umständlich die Makros erstellen. Gibt es da vllt. eine Möglichkeit wie man das z.B. direkt mit einer new-Funktion verbinden kann? Dazu müsste ich eine Art Oberliste haben, da ich ja sonst keine Struktur hab, mit der ich den Pointer von new() entgegen nehmen könnte. Kann man da irgendwie was drehen?

    Ein weiteres Problem liegt in gen.c (z.B. Zeile 29). Dort rufe ich eine Funktion auf, die nur mit Strings zusammenarbeitet. Ich hab schon versucht mit dem Präprozessor den Typ des generischen T abzufragen, das kann ich aber nicht innerhalb eines anderen Makros machen. Wie könnte man diese Spezialisierung auf einen bestimmten Datentyp umgehen bzw. auslagern? Geht da vllt. was mit Funktionspointer?

    Und noch was: In Zeile 17 von gen.c darf ich kein Strichpunkt ans Ende des Makros setzen, da dieses außerhalb der Funktion wäre. Gibt es da eine Möglichkeit das zu umgehen (und gleichzeitig C90 konform zu bleiben) oder muss ich damit leben?

    Der Code ist ausführbar:

    gen.h

    #ifndef _GEN_H_
    #define _GEN_H_
    
    typedef char *string_t;
    
    #define _GEN_OBJ(T) \
        T(int); \
        T(float); \
        T(string_t)
    
    #define _LIST_CREATE_TEMPLATE(T) \
        typedef struct _ListNode_##T { \
            struct _ListNode_##T *next; \
            T data; \
        } ListNode_##T; \
        \
        typedef struct _List_##T { \
            int size; \
            ListNode_##T *node; \
        } List_##T; \
        \
        List_##T *List_##T##_new(); \
        void List_##T##_add(List_##T *list, T data); \
        void List_##T##_printAll(List_##T *list); \
        void List_##T##_del(List_##T *list)
    
    _GEN_OBJ(_LIST_CREATE_TEMPLATE);
    
    /*
    _LIST_CREATE_TEMPLATE(int);
    _LIST_CREATE_TEMPLATE(float);
    _LIST_CREATE_TEMPLATE(string_t);
    */
    
    #endif
    

    gen.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "gen.h"
    
    #define _LIST_NEW(T) \
        List_##T *List_##T##_new() { \
            List_##T *l = NULL; \
            if (!(l = malloc(sizeof(List_##T)))) {\
                fprintf(stderr, "no memory for List.\n"); \
            } \
            l->size = 0; \
            l->node = NULL; \
            return l; \
        }
    
    _LIST_NEW(string_t)
    
    #define _LIST_ADD(T) \
        void List_##T##_add(List_##T *list, T data) { \
            if (!list) { \
                fprintf(stderr, "List does not exist.\n"); \
                return; \
            } \
            if (!list->node) { \
                if (!(list->node = malloc(sizeof(ListNode_##T)))) { \
                    fprintf(stderr, "no memory for ListNode.\n"); \
                } \
                if (!(list->node->data = calloc(strlen(data), sizeof(data)))) { \
                    fprintf(stderr, "no memory for data.\n"); \
                } \
                strcpy(list->node->data, data); \
                list->node->next = NULL; \
                list->size = 1; \
            } else { \
                ListNode_##T *node = list->node; \
                \
                while (node->next) { \
                    node = node->next; \
                } \
                \
                if (!(node->next = malloc(sizeof(ListNode_##T)))) { \
                    fprintf(stderr, "no memory for ListNode.\n"); \
                } \
                if (!(node->next->data = calloc(strlen(data), sizeof(data)))) { \
                    fprintf(stderr, "no memory for data.\n"); \
                } \
                node = node->next; \
                strcpy(node->data, data); \
                node->next = NULL; \
                list->size += 1; \
            } \
        }
    
    _LIST_ADD(string_t)
    
    #define _LIST_PRINT_ALL(T) \
        void List_##T##_printAll(List_##T *list) { \
            ListNode_##T *e = NULL; \
            \
            if (!list) { \
                fprintf(stderr, "List does not exist.\n"); \
                return; \
            } \
            e = list->node; \
            \
            while (e) { \
                printf("%s\n", e->data); \
                e = e->next; \
            } \
        }
    
    _LIST_PRINT_ALL(string_t)
    

    main.c

    #include "gen.h"
    
    int main(int argc, char **argv)
    {
        List_string_t *ls = List_string_t_new();
        List_string_t_add(ls, "Hello");
        List_string_t_add(ls, "World");
        List_string_t_printAll(ls);
        return 0;
    }
    

Anmelden zum Antworten