仅在API中公开void指针

时间:2014-02-13 00:08:10

标签: c api void

我见过很多C库,它们没有将它们在内部处理的对象作为不同的类型呈现,而是在让你访问它们之前用void指针包装它们。在实践中,“私有”源文件看起来像:

typedef struct {
    int value;
} object;

void * object_new(void)
{
    object *o = malloc(sizeof(object));
    o->value = 1;
    return o;
}

int object_get(void *o)
{
    return (object *)o->value;
}

void * object_free(void *o)
{
    free(o);
}

在主标题中你只有:

void * object_new(void);
int object_get(void *o);
void * object_free(void *o);

现在我想知道:他们这样做有什么特别的原因吗?如果想要确保API用户无法访问对象的内部,仅仅在主库头中公开类型名称并隐藏底层结构的详细信息(或者其他任何内容)是不够的。实际文件中的实际对象?

3 个答案:

答案 0 :(得分:5)

隐藏void指针后面的类型的原因可能是(误导)企图隐藏(modular programming)内部细节。这很危险,因为它抛出了编译器可能会在窗口外执行的任何类型检查。

更好的事情就是这样:

for-user.h

struct internalstuff;
void somefunc(struct internalstuff *p);

for-internal-use.h

#include "for-user.h"

struct internalstuff { ...};

implementation.c

#include "for-internal-use.h";


void somefunc(struct internalstuff *p)
{
   ...
}

这样,没有人会将internalstuff与随机字符串或malloc(3)的原始结果混淆,而不会至少收到警告。只要你在C中只提到指向struct internalstuff的指针就可以了,不要手头有struct的定义。

可以使用class在C ++中完成同样的事情,如果Objective C不允许这样做,我会感到很惊讶。但面向对象编程语言有自己的,更灵活的工具。在那里,您可以定义要导出的简单基类,同时使用内部扩展。看一下好的C ++书籍了解详情(这里有广泛的列表)。

答案 1 :(得分:1)

在一个对象世界(Obj-C和C ++)中,我认为其原因主要与继承有关。如果从基类创建子类,则在创建类的新实例时,返回值的类型没有问题。由于没有显示内部细节或创建依赖关系,因此只有直接C,似乎没有明确的原因。

答案 2 :(得分:1)

你是对的..大多数情况下的想法是限制API用户从对象的内部。关于类型名称的决定实际上只是风格问题。如果您按照建议(某些API执行)在标题中公开类型名称,它可能看起来像:

typedef void* object;

从编译器的角度来看,没有真正的优点或缺点。虽然它确实让API用户更好地了解正在发生的事情:

object object_new(void);
int object_get(object o);
void object_free(object o);