【问题标题】:Setting pointer type at compile time在编译时设置指针类型
【发布时间】:2020-06-06 14:09:45
【问题描述】:

我想创建一个通用的链表。该列表只需要包含一种类型,但该类型需要由程序员定义。我想要做的是允许程序员调用宏SETTYPE(T),其中T 将是列表将保存的数据类型。在下面的代码中,我想将node struct 中的void * 替换为程序员提供的类型。代码被破坏了,但我只想给出我想要实现的目标。帮助将不胜感激。

#ifndef TYPE
#define TYPE
#define SETTYPE(T) T
typedef struct node {
    T *data;
    struct node *next;
} node;
typedef node *list;
#endif

node *new_node(void *data) {
    node *_l = malloc(sizeof *_l);
    _l->data = malloc(*data);
    memcpy(_l->data, data, sizeof(*data));
    _l->next = NULL;
    return _l;
}

【问题讨论】:

    标签: c macros compile-time


    【解决方案1】:

    您需要为整个链表使用带有“define”的自动生成代码 - 这意味着在#define 中创建每个方法和结构,以便在编译时编译器将知道要使用哪种类型 例如:

    // type_list.h
    #define define_list(T) \
    typedef struct { \
        T* data; \
        struct node* next; \
    } list_##T;
    

    上面的代码可以这样调用:

    #include <stdio.h>
    #include "type_list.h"
    
    define_list(int)
    define_list(float)
    
    // This is the developer you want to help
    int main(int argc, char const *argv[])
    {
        list_int *a;
        list_float *b;
        return 0;
    }
    

    有关如何创建自动生成代码的更多信息,请查看这篇文章:

    Simulation of templates in C (for a queue data type)

    希望有所帮助

    【讨论】:

    • 让我们听听更多人的意见。
    • 请注意,您需要额外的 typedef 来定义指针列表、unsigned long 列表、long long 列表...
    【解决方案2】:

    已经提供给您的解决方案的替代方案涉及将类型标识符连接到所涉及的类型(我还应该在我的解决方案中命名该结构,但我不会更正我的同事@AmitBerger,给出了很好的解决方案)

    此解决方案允许您将节点链接到多个列表(不是通过引用),并允许您创建一个全局列表(或者,通常不是动态分配的内存),甚至是它的混合。

    我的解决方案有点不同。前段时间,我根据从 linux 内核中提取的一个想法写了一个链接列表的解决方案,我将在下面复制。解决方案正好相反,只需定义一个节点结构,并将其嵌入(该节点可以属于列表的次数)到您类型的结构中。这样,您可以拥有属于多个列表的节点,只有在您最终结束存储对实际节点的引用时才能拥有这些列表(如果您实施其他答案提出的解决方案)。 (这在内核中的数据结构中经常使用,无论是 linux 还是其他)

    #ifndef LISTS_H
    #define LISTS_H
    
    #include <assert.h>
    
    typedef struct LNODE_S {
            struct LNODE_S *n_prev;
            struct LNODE_S *n_next;
    } LNODE_T, *LNODE_P;
    
    typedef struct LIST_S {
        size_t  l_size;
        LNODE_P l_first;
        LNODE_P l_last;
    } LLIST_T, *LLIST_P;
    
    #ifndef OFFSETOF
            /* gives the offset of field f in type T */
    #define OFFSETOF(T,f) ((char*)&(((T*)0)->f)-(char*)0)
    #endif
    
            /* initialize fields of list L */
    #define LIST_INIT(L) do{                  \
            (L)->l_size=0;                    \
            (L)->l_first=(L)->l_last=0;       \
        }while(0)
    
    /* list declaration (with initializer) */
    #define LIST_DECLARE(L)                   \
        LLIST_T L={                           \
            .l_size=0,                        \
            .l_first=0,                       \
            .l_last=0\
        }
    
    /* get first, next, prev or last nodes of a list */
    #define LIST_FIRST(L) ((L)->l_first)
    #define LIST_LAST(L) ((L)->l_last)
    #define LIST_NEXT(N) ((N)->n_next)
    #define LIST_PREV(N) ((N)->n_prev)
    
    /* get the list node correspondent to list tagged F of struct element passed as E */
    #define LIST_NODE(E,F)      ((LNODE_P)&(E)->F)
    /* get the corresponding struct element to a list node N (embedded as field F) */
    #define LIST_ELEMENT(N,T,F) ((N)?(T*)((char*)(N)-OFFSETOF(T,F)):0)
    
    /* first element of list L (tagged as L field in T) of type T */
    #define LIST_FIRST_ELEMENT(L,T,F) (LIST_ELEMENT(LIST_FIRST(L),T,F))
    #define LIST_LAST_ELEMENT(L,T,F) (LIST_ELEMENT(LIST_LAST(L),T,F))
    #define LIST_NEXT_ELEMENT(E,T,F) (LIST_ELEMENT(LIST_NEXT(LIST_NODE(E,F)),T,F))
    #define LIST_PREV_ELEMENT(E,T,f) (LIST_ELEMENT(LIST_PREV(LIST_NODE(E,F)),T,F))
    
    /* for(;;) loop, you add the body after the macro call. Nodes */
    #define LIST_FOREACH(p, L) for(p=LIST_FIRST(L);p;p=LIST_NEXT(p))
    #define LIST_FORBACK(p, L) for(p=LIST_LAST(L);p;p=LIST_PREV(p))
    /* idem, but you get the element of type T reference */
    #define LIST_FOREACH_ELEMENT(p,L,T,F) for(p=LIST_FIRST_ELEMENT(L,T,F);p;p=LIST_NEXT_ELEMENT(p,T,F))
    #define LIST_FORBACK_ELEMENT(p,L,T,F) for(p=LIST_LAST_ELEMENT(L,T,F);p;p=LIST_PREV_ELEMENT(p,T,F))
    
    /* check for emptyness */
    #define LIST_EMPTY(L) (!(L)->l_size)
    
    /* list insertion/append */
    #define __LIST_COMMON_INSERT(L,N,fst,lst,nxt,prv) do{   \
            (N)->nxt = (L)->fst;                            \
            (N)->prv = 0;                                   \
            if ((L)->fst)                                   \
                (L)->fst->prv=(N);                          \
            else                                            \
                (L)->lst=(N);                               \
            (L)->fst=(N);                                   \
            (L)->l_size++;                                  \
        }while(0)
    #define LIST_INSERT(L,N) __LIST_COMMON_INSERT(L,N,l_first,l_last,n_next,n_prev)
    #define LIST_APPEND(L,N) __LIST_COMMON_INSERT(L,N,l_last,l_first,n_prev,n_next)
    
    /* node unlink */
    #define __LIST_COMMON_UNLINK(L,N,lst,nxt,prv)           \
            if ((N)->nxt) (N)->nxt->prv = (N)->prv;         \
            else {                                          \
                if((L)->lst != (N)) break;                  \
                (L)->lst = (N)->prv;                        \
            }
    
    #define LIST_UNLINK(L,N) do{                            \
            if (!(L)->l_size) break;                        \
            __LIST_COMMON_UNLINK(L,N,l_last,n_next,n_prev); \
            __LIST_COMMON_UNLINK(L,N,l_first,n_prev,n_next);\
            (L)->l_size--;                                  \
            (N)->n_next = (N)->n_prev = 0;                  \
        } while(0)
    
    /* same for elements, you provide the list reference, Element reference, type of elements, (F)ield name of the list nodes in T */
    #define LIST_INSERT_ELEMENT(L,E,T,F) LIST_INSERT(L,LIST_NODE(E,F))
    #define LIST_APPEND_ELEMENT(L,E,T,F) LIST_APPEND(L,LIST_NODE(E,F))
    #define LIST_UNLINK_ELEMENT(L,E,T,F) LIST_UNLINK(L,LIST_NODE(E,F))
    
    #endif /* LISTS_H */
    

    这个模块的使用(只是一个头文件)如下所示:

    /* Standard include files */
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <time.h>
    #include "lists.h"
    
    /* type of elements we are double linking. */
    struct nodo {
            int     num;
            LNODE_T node; /* list nodes, just two pointers */
    };
    
    LIST_DECLARE(lista_nodos); /* declaration and initialization */
    
    /* adding a node */
    struct nodo *add(int num) {
        struct nodo *n = malloc(sizeof *n); /* get a node, you don't need to malloc, it can be a global. */
        n->num = num;
        LIST_APPEND_ELEMENT(&lista_nodos, n, struct nodo, node);
        return n;
    }
    
    void list(){
        struct nodo *n;
        printf("size=%d: ", lista_nodos.l_size);
    
        /* foreach loop, n is the iterator, and you must specify the type and the field in the type that has the pointers. */
        LIST_FOREACH_ELEMENT(n, &lista_nodos, struct nodo, node) {
            printf("<%d>", n->num);
        }
        printf(";\n");
    }
    
    int main (int argc, char **argv)
    {
        struct nodo *n;
        add(1); list();
        add(2); list();
        add(3); list();
    
        while(n = LIST_FIRST_ELEMENT(&lista_nodos, struct nodo, node)) {
            LIST_UNLINK_ELEMENT(&lista_nodos, n, struct nodo, node);
            list();
        }
    
        add(4); 
        list();
    
        n = add(5); 
        list();
    
        add(6); 
        list();
    
        LIST_UNLINK_ELEMENT(&lista_nodos, n, struct nodo, node); list();
    
        while(n = LIST_LAST_ELEMENT(&lista_nodos, struct nodo, node)) {
            LIST_UNLINK_ELEMENT(&lista_nodos, n, struct nodo, node); 
            list();
        }
    } /* main */
    

    如果您想下载此代码,it is stored in my repository in github。您可以免费下载和使用它,它的版权归我所有,并且可以在 BSD 许可下使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-10
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      相关资源
      最近更新 更多