良好的“重叠”功能库设计

时间:2011-01-05 16:10:28

标签: c

我正在尝试创建一个库,它提供了一个简单的链表实现,还有一些链表的概括,比如堆栈和队列,都基于基本的链表。

问题是,我希望有不同类型的自己的“私有”函数,所以你不会使用“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);
}

如果我想从基本列表中专攻,或者是否有一个漂亮而干净的方式,这是一个我不得不忍受的开销吗?

3 个答案:

答案 0 :(得分:1)

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

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

inline void queue_dispose(queue **Q, void (*free_content)(void *)) {
      list_dispose(&&(*Q->base), free_content);
}

这将确保您获得相同级别的类型检查,但没有运行时头顶或额外代码。除非您使用指向这些函数的指针,否则不应该遇到问题,如果您是,那么您也可以为它们包含常规实现。

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

答案 1 :(得分:1)

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

typedef struct queue
{
    list_node *queue_head;
} queue;

typedef struct stack
{
    list_node *stack_head;
} stack;

单独的结构是非常合适的 - 例如,一个堆栈只需要一个头指针,但如果它有一个指向列表的头部和尾部指针,那么队列会更有效。

答案 2 :(得分:0)

如果您可以通过编译器进行较少的类型检查,则可以使用typedef而不是包装结构,例如。
typedef struct queue list
#define queue_create list_create

inline queue *queue_create() {return (queue *) list_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 ++。)