I have been forced into programming C++ for years and now I am coming back to C11 which is quite new to me after having only known C89 before coming to C++. Still... as a hardcore assembler programmer, it feels like coming home.
One thing I liked a lot about C++ was the ability to create PIMPL idioms. There seems to be several ways to do it, but I used to write a purely abstract (definition-)class in the header file which contained only what the user would see and need, and in the CPP file there was an inheriting class which contained all the stuff that the user should never see, which I incorrectly call the 'hidden dirty code behind the definition' (because there should never be dirty code of course). A factory function created an instance of this class.
I like to see this in C (without all the C++ disadvantages) and I am trying to do it as a test with implementing my own string handling API.
So I created a typedef void* dstr and added a bunch of functions like:
void dstr_free(dstr s);
dstr dstr_new(size_t reserve);
dstr dstr_from_cstr(const char *cstr);
dstr dstr_asprintf(const char *fmt, ...);
dstr dstr_vasprintf(const char *fmt, va_list varptr);
void dstr_concat_cstr(dstr *s, const char *cs);
void dstr_concat_dstr(dstr *s, const dstr cs);
const char *dstr_cstr(const dstr s);
...
The thing about this is that it enables me to implement dstr in any way I want without the user knowing how and without the user being able to fiddle with its internals (without hacking the memory of course). Later on, I can change the whole implementation and the user wouldn't need to know.
The user doesn't know that the dstr typedef is being cast to a variable sized dstr_s struct (in the C file) which contains all the necessary optimization values and that this same pointer already contains the string itself (see EDIT below - I changed this because I understand that this isn't a good idea).
But, would I change this system so that the string itself moves to a separate pointer, the user wouldn't notice and wouldn't have to change his code or even need to glance at the changes because the only thing he sees is that dstr is just a void*.
The question is: is this a bad idea? I worry a bit about it actually being a void* (coming from C++, I don't really know how much type safety I need to let go of, coming from Assembler, this seems perfectly fine). Any other reasons why this would be a bad idea?
And aside from that question: any comments/remarks on this? They are certainly welcome as I am trying to learn.
EDIT:
I just found out for myself that ingraining the string itself into a variable sized struct was not a good idea because its pointer may change, invalidating all references to it (dstrlist for example), so I'll be changing that. The question does remain valid though.