سؤال

I've seen a good deal of C libraries that do not present the objects they deal with internally as distinct types, but instead wrap them with void pointers before letting you access them. In practice, the "private" source files look something like:

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);
}

And in the main header you have only:

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

Now I wonder: is there a particular reason they do so? If the idea is to ensure the API user has no access to the internals of the object, isn't it sufficient to only expose the type name in the main library header, and to hide the details of the underlying structure (or whatever be the actual object) in the implementation files?

هل كانت مفيدة؟

المحلول

The reason to hide the types behind void pointers could be a (misguided) attempt to hide (in the sense of modular programming) the internal details. This is dangerous, as it throws any type checking the compiler might do right out the window.

Better would be something along the lines:

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)
{
   ...
}

This way nobody will mix up internalstuff with a random string or the raw result from malloc(3) without getting at least a warning. As long as you only mention pointers to struct internalstuff in C it is fine not to have the definition of the struct at hand.

Something along the same lines can be done in C++ with class, and I'd be suprised if Objective C doesn't allow the same. But the object oriented programming languages have their own, much more flexible, tools for this. There you can define a bare-bones base class to export, while internally extensions are used. Take a look at a good C++ book for details (there are extensive lists here).

نصائح أخرى

In a world of objects (Obj-C and C++), I believe the reason is mostly to do with inheritance. If a subclass is created from the base class, then there is no problem with the type of the return value when creating a new instance of the class. With just straight C, there does not appear to be a clear cut reason as no internal details are revealed or dependencies created.

You're correct.. the idea in most of these cases is to restrict the API user from the internals of the object. The decision about type names though really is just a matter of style. If you were to expose the type name in the header as you suggest (which some APIs do), it would probably look something like:

typedef void* object;

There is no real advantage or disadvantage to doing this from the compiler's point of view. Although it does give the API user a better understanding of what's going on:

object object_new(void);
int object_get(object o);
void object_free(object o);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top