Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 良好的图书馆设计;重叠“;功能_C - Fatal编程技术网

C 良好的图书馆设计;重叠“;功能

C 良好的图书馆设计;重叠“;功能,c,C,我正在尝试创建一个库,它提供了一个简单的链表实现以及链表的一些泛化,比如堆栈和队列,所有这些都基于基本链表 问题是,我希望有不同的类型和它们自己的“私有”函数,这样您就不会使用“stack_pull(my_queue);”或“queue_pull(my_stack)”,这将导致该特定类型列表的错误行为。我现在能想象的唯一方法是,将基本链表结构包装到其他结构中,用于它们自己的类型,基本上就是这样 typedef struct node { void *data; list_node

我正在尝试创建一个库,它提供了一个简单的链表实现以及链表的一些泛化,比如堆栈和队列,所有这些都基于基本链表

问题是,我希望有不同的类型和它们自己的“私有”函数,这样您就不会使用“stack_pull(my_queue);”或“queue_pull(my_stack)”,这将导致该特定类型列表的错误行为。我现在能想象的唯一方法是,将基本链表结构包装到其他结构中,用于它们自己的类型,基本上就是这样

typedef struct node
{
    void *data;
    list_node *next;
} list_node

typedef struct list
{
    list_node *root;
} linked_list;

typedef struct queue
{
    linked_list *base;
} queue;

typedef struct stack
{
    linked_list *base;
} stack;

linked_list *list_create();
void list_dispose(linked_list **, void (*free_content)(void *));

queue *queue_create();
void queue_dispose(queue **, void (*free_content)(void *));

stack *stack_create()
void stack_dispose(stack **, void (*free_content)(void *));
这样,我必须编写专门的函数,以利用基函数和常量展开来获取实际数据,例如

queue *queue_create()
{
    [...] /* Allocate a new queue struct */
    tmp_queue->base = list_create();
    [...]
    return tmp_queue
}

void *stack_pull(stack *s)
{
    [...] /* Error checking */
    return list_pop_last(s->base);
}

void *queue_pull(queue *q)
{
    [...] /* Error checking */
    return list_pop_first(s->base);
}

如果我想从基本列表中进行专门化,这是我必须承受的开销吗?还是有一种好的、干净的方法?

如果你不介意编译器进行较少的类型检查,你可以使用
typedef
s而不是包装结构,例如
typedef结构队列列表

\define queue\u create list\u create


inline queue*queue\u create(){return(queue*)list\u create

-后一个选项需要C99或C89的扩展

如果有
inline
关键字,还可以将操作包装到宏中:

#define WRAP_LIST(wrapper)                                  \
    struct wrapper {linked_list *root;};                    \
    inline struct wrapper *wrapper ##_create {              \
        …                                                   \
        tmp_queue->base = list_create();                    \
        …                                                   \
    }                                                       \
    …                                                       \
    typedef struct wrapper wrapper
// note lack of ‘;’ at end of last line

WRAP_LIST(queue);
WRAP_LIST(stack);

(或使用C++)

在另一个结构中包装列表结构是一个很好的处理方法。因为内外结构的对齐和填充要求应该完全相同,所以不应该有额外的运行时开销或内存使用(因为外部结构的对齐和填充只来自内部结构)。

对于处理这些函数/方法的函数/方法,您可以使用
inline
消除堆栈或队列函数只是简单重命名(或特殊调用)或列表函数的情况下可能产生的任何开销

inline void queue_dispose(queue **Q, void (*free_content)(void *)) {
      list_dispose(&&(*Q->base), free_content);
}
这将确保您获得相同级别的类型检查,但没有运行时开销或额外的代码。除非您使用指向这些函数的指针,否则您不应该遇到问题,如果是,那么您也可以为它们包含常规实现


您应该注意到,在列表结构中放置节点指针作为唯一成员已经是一个应用程序,与在堆栈或队列结构中包装列表相同。

这种方法很好,只是不需要
链接列表
结构-这是一个不必要的间接级别。列表是完整的y由其头指针描述,因此您只需要在堆栈和队列中包含头指针:

typedef struct queue
{
    list_node *queue_head;
} queue;

typedef struct stack
{
    list_node *stack_head;
} stack;

单独的结构是非常合适的-例如,堆栈只需要一个头指针,但如果队列同时有指向列表的头指针和尾指针,则队列效率更高。

实际上,我在这个问题中简化了结构,我的实际链表还包含一个长度字段,这样就不必遍历整个列表来计算队列的数量其中的元素!