Up to now, I've been using void *
as a way to encapsulate private data in C. The idea is : the user should not bother with the internal, and just request exposed functions.
Hence for example :
typedef void* myPrivateType;
myPrivateType createMPt(int someArg);
int doSomething(myPrivateType mpt, int someOtherArg);
void freeMpt(myPrivateType mpt);
This works well at hiding the internal of myPrivateType
. However, there is one last minor catch : void*
is so permissive, that the compiler will silently accept any kind of pointer, and not trigger any warning in case of incorrect type.
This looks like a small issue, but it just increases the likelyhood that a user improperly uses the interface and lose a lot of time trying to debug what's wrong.
As a consequence, I'm now leaning on using incomplete types instead of void*
, as a stricter way to control type during compilation.
Hence the previous example becomes as follows :
typedef struct foo* myPrivateType;
myPrivateType createMPt(int someArg);
int doSomething(myPrivateType mpt, int someOtherArg);
void freeMpt(myPrivateType mpt);
As you can see, almost nothing has changed, only the typedef. It works better than previous example as now, if the user provides another pointer than `myPrivateType', the compiler will complain, and the error will be immediately caught.
This is a fairly good alternative. Except that, in the "private section" of the code (the .c
file), I will have to define what struct foo
is. In some cases, it's quite straightforward, when such content is clearly and statically defined.
But sometimes, the content of myPrivateType
depends on some variable provided at runtime, and therefore its size may vary. This is no good for a C struct
, which is supposed to have a defined size at compilation time.
As a workaround, I could for example typedef myPrivateType this way :
typedef size_t* myPrivateType;
or
typedef size_t myPrivateType[]; // equivalent
This let the possibility to decide the size later on, as a multiple of size_t
. But now, myPrivateType
is more permissive, as any size_t*
pointer will also fit the bill.
I'm wondering if there is a way to combine both properties, with myPrivateType
being very strict, hence impossible to confuse with any other type of pointer, but the underlying private data keeping the ability to select its size at runtime.
How about:
Use in essentially exactly the same way that you used to use the raw void pointer. You can expose the whole struct in the header, since there's nothing much the application can do with the void pointer it contains anyway.
This solves the problem of implicit conversions with void * without introducing any irritations beyond the mpt->private dereference within your library functions.
edit: with the
typedef struct myPrivateType myPrivateType;
construct if you prefer.