我想用C编写一个库,我不知道推荐的方法是什么。我得到了例如结构和多个这样的函数:
typedef struct example
{
int *val;
struct example *next;
} Example;
我已经为多种类型的 val
构建了函数Example* build() { do sth };
Example* buildf() { do sth }; // val is float
Example* buildd() { do sth }; // val is double
什么是更好的做法(用于“专业”库)。使用指向void和cast的指针或具有所有可能性的结构 - int,float,double。
答案 0 :(得分:2)
使用union
和某种方式存储类型信息:
typedef struct example
{
enum{ T_STRUCT_WITH_INT, T_STRUCT_WITH_FLOAT, T_SO_ON } type;
union {
int val_int;
float val_float;
} val;
struct example *next;
} Example;
按type
s->val.val_int
后访问字段
在C11中,您可以使联合匿名,并且可以像s->val_int
答案 1 :(得分:1)
这主要基于意见,经验和手头的具体要求的某种组合。
Jacob Navia的一些容器库工作启发了以下方法。我自己从未使用过它:
struct container_node {
struct container_node *link_here, *link_there, *link_elsewhere;
/*...*/
char data[0]; /* C90 style of "flexible array member" */
};
struct container_node *container_node_alloc(size_t data_size);
分配函数将节点分配得足够大,以便data[0]
到data[data_size-1]
个字节的存储空间可用。通过另一组API函数,可以复制任意类型的用户数据。
以下方法有时被称为“侵入式容器”。容器仅定义由链接结构组成的“基类”。用户必须将此结构嵌入到自己的结构中:
struct container_node {
struct container_node *next, *prev;
};
void container_insert(struct container *container, struct container_node *n);
struct container_node *container_first(struct container *container);
用户执行此操作:
struct my_widget {
struct container_node container_links;
int widget_height;
/* ... */
};
/* .... */
/* We don't insert my_widget, but rather its links base. */
container_insert(&widg_container, &widget->container_links);
一些宏用于在指向窗口小部件的指针和指向容器链接的指针之间进行转换。请参阅Linux内核中广泛使用的container_of
宏:
struct my_widget *wptr = container_of(container_first(&widg_container),
struct my_widget, container_links);
请参阅this question。
然后存在在每个节点中存储union
的方法,其提供整数,浮点值或指针。在这种情况下,数据是单独分配的(尽管不一定:如果调用者控制节点的分配,仍然可以将节点结构和用户数据放在来自单个malloc
调用的缓冲区中)。
最后,还有一些方法将这些技术与预处理器模板包装在一起,其中一个例子是BSD QUEUE macros。