When writing a library, you sometimes want to hide implementation details from the user. The ideal tool for this is opaque structs or opaque pointers.
A problem arises when another source file in the library wishes to use data from this struct. For example: this is the header file apple.h
:
typedef struct apple_ Apple;
Apple* new_apple();
void delete_apple(Apple* a);
/* ... */
This is the definition of the struct Apple
:
typedef struct apple_ {
int taste; /* the higher the better */
}
Typically, this part resides in apple.c
.
But what if a Store
wishes to rank their apples according to taste? This could be store.c
:
#include "apple.h"
void rankApples(Store* store) {
int t = store->apples[0]->taste; /* unreachable field */
}
A solution could be to duplicate the struct definition (I don't want that) or to create a function in apple.[hc]
: int taste_apple(Apple* a) { return a->taste; }
, but I'd rather that users don't know how tasty apples are.
How can this be solved? Should I create another header file used by both apple.c
and store.c
? How do I stop users from including that header file?
When hiding library detail from consuming clients, it is not uncommon to do what you described in your last paragraph. But you don't need to "ship the details" with your lib and public header.
For example:
mylib.h
mylibint.h
mylib.c
In doing so, your library will build, consuming both headers while doing so. The only header you need to ship with it is
mylib.h
. Later, a client can do this:client.c
And they are left blissfully unaware of what
Data
is besides some opaque type.