0

I'm not even sure how to properly formulate question about this.

I'm writing a library where I have multiple implementations (multiple libraries out of one). I want to hide as much as possible, if not all, implementation details from client app, in order to write an app disregarding implementation details.

It's all fine when implementation is contained within one function. However, often I need to instantiate a struct from library, do something to it with a function from library, resume writing app as normal, and then return to a function from library with data from previous function from library.

Struct details are important ONLY to library functions. I don't need to see or touch those from client application apart from passing them around because of this.

So, is there a way to hide struct details from client app and still be able to use it or if there's another way of doing this by some form of encapsulation or maybe even some kind of data (globals?) visible only to library?

Here's my lame illustration example with code:

/*
library_private.h
*/
#if (A)
{
    struct mystruct_t {
        A *something;
    }
}
#else
    struct mystruct_t {
        B *something;
    }
#endif

/*
library_public.h
*/
struct mystruct_t;

/*
library.c
*/
struct mystruct_t* create() {

    struct mystruct_t *handle = malloc(sizeof(struct mystruct_t));

    return handle;
}

/*
client.h
*/

struct mystruct_t;
/* but, I need a definition, so I have to repeat either from library_private.h */

/*
client.c
*/

int main(int argc, char const *argv[]) {

    struct mystruct_t *handle = create();

    /*...*/

    something(handle);

    return 0;
}
Keyframe
  • 1,390
  • 1
  • 14
  • 28

2 Answers2

0

Cast to a void * when returning and back to structure mystruct_t just after passing into a function. This is not great as you will loose some of the compiler type checking.

Simon Black
  • 913
  • 8
  • 20
  • Ok, that seems to be an option and working. I'll see if there are any better options before closing. Thanks! – Keyframe Sep 22 '16 at 21:40
  • I would not recommend this. I suspect the probability of passing the wrong `void*` to the wrong function is *much* greater than "accidentally" accessing the struct when you are trying not to. – EOF Sep 22 '16 at 21:43
  • What would you recommend then to keep data between library calls and at the same time hide implementation specifics from the client and avoid globals in library? – Keyframe Sep 22 '16 at 21:46
  • @MathAgain *Why* do you even need to hide the implementation? Do you really have such poor impulse control that you must fear that your Mr. Hyde-like alter ego will at some point start messing with the structs in a context where it shouldn't? Anyway, there are already [questions](http://stackoverflow.com/q/26090562/3185968) about this. – EOF Sep 22 '16 at 21:49
  • A simple way to have both type safety and implementation hiding is to pass around *by value* a struct that contains the pointer (using a different struct for each handle type). – Matteo Italia Sep 22 '16 at 21:59
  • 2
    Hiding implementation is very useful when the type of members are too complex and would require include a lot of other headers and also for dynamic library upgrade: you cannot maintain ABI compatibility if the struct members are part of your API (because user code may depend upon them), so users must recompile the client program every time they upgrade the library. – André Sassi Sep 22 '16 at 22:17
0

client.c (or client.h) should include library_public.h. There is no need to have the structure definition. Only its declaration struct mystruct_t; is enough to use pointers to the structure. Of course, you cannot access its members, but that is exactly what you want in this case.

André Sassi
  • 1,076
  • 10
  • 15