I want to hide the internal type from the user of a library.
Currently I have something like this:
foo.h
typedef struct public
{
uint16 a;
//...
unsigned char internals[4];
} public_type;
foo.c
typedef struct public
{
uint32_t a;
}internals_type;
Then in the functions, I'm doing a cast like.
void bar(public_type * const public_struct)
{
internals_type* const internals = &public_struct->internals;
intrnals->a = getSomething();
// .....
}
Is there a better way of doing this?
I've tried some weird stuff with unions and pointers in the header, but nothing seems to be better and I'm curious if this can get any cleaner or at least if the warnings from casting a pointer from one type to pointer to another could be removed.
I suggest you read more about opaque data types, and consider e.g. the FILE
structure.
In short, don't split your structure into "public" and "private" variants (that way lies madness and possible undefined behavior). Instead just declare a structure in a public header file, and have your functions return pointers to that structure or accept arguments that are pointers to that structure.
Then internally in the library you have a private header file which have the definition of the structure, and use that header file for your implementation.
#ifndef PUBLIC_HEADER_FILE_H
#define PUBLIC_HEADER_FILE_H
typedef my_private_structure MY_PUBLIC_TYPE;
MY_PUBLIC_TYPE *mylib_create(void);
void mylib_destroy(MY_PUBLIC_TYPE *ptr);
#endif
#ifndef PRIVATE_HEADER_FILE_H
#define PRIVATE_HEADER_FILE_H
#include "public_header_file.h"
struct my_private_structure
{
// Some private fields here
};
#endif
#include "private_header_file.h"
#include <stdlib.h>
MY_PUBLIC_TYPE *mylib_create(void)
{
MY_PUBLIC_TYPE *ptr = malloc(sizeof *ptr);
return ptr;
}
void mylib_destroy(MY_PUBLIC_TYPE *ptr)
{
free(ptr);
}
You distribute public_header_file.h
together with your library. It's the header file that the users of the library will use.
The source of your library, and especially the private_header_file.h
file should not be distributed, or at least not installed if you make an open-source library.
Note that this scheme make all of the structure "private", which is usually a good idea since then you can modify it as you like without the users of the library needing to rebuild their applications using your library. To access members of the private structure you can use functions which simply returns the value of whatever member needs to be accessed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With