jonbovy jonbovy - 4 months ago 14
C Question

How to make a typedef as private as possible without using Malloc?

I am looking for a way to make private style typedefs that can only be accessed or manipulated from a specific set of function calls (setBit(bit_typ *const t), getBit(bit_typ *const t)). I am looking for a way to do this without using malloc, does anyone have any ideas?

EDIT:// this question is different than this one because it is looking for ways to get as close to a "private" structure whereas the other question (TL;DR is there a way to define an opaque type which can nonetheless be allocated on stack, and without breaking strict aliasing rule ?) looks for a solution to a problem related to one possible solution to my question.

AnT AnT
Answer

One way to do it is to expose the total size of the opaque type and make used declare the objects of your opaque type as unsigned char [N] buffers. For example, let's say you have some type OpaqueType, internals of which you want to hide from the user.

In the header file (exposed to the user) you do this

typedef unsigned char OpaqueType[16];

where 16 is the exact byte-size of the type you want to hide. In the header file you write the whole interface in terms of that type, e.g.

void set_data(OpaqueType *dst, int data);

In the implementation file you declare the actual type

typedef struct OpaqueTypeImpl
{
  int data1;
  double data2;
} OpaqueTypeImpl;

and implement the functions as follows

void set_data(OpaqueType *dst, int data)
{
  OpaqueTypeImpl *actual_dst = (OpaqueTypeImpl *) dst;
  actual_dst->data1 = data;
}

You can also add a static assertion that will make sure that sizeof(OpaqueType) is the same as sizeof(OpaqueTypeImpl).

Of course, as it has been noted in the comments below, extra steps have to be taken to ensure the proper alignment of such objects, like _Alignas in C11 or some union-based technique in "classic" C.

That way you give the user opportunity to declare non-dynamic object of OpaqueType, i.e. you don't force the user to call your function that will malloc such objects internally. And at the same time you don't expose to user anything about the inner structure of your type (besides its total size and its alignment requirement).

Note also that OpaqueType declared in that way is an array, meaning that it is not copyable (unless you use memcpy). That might be a good thing, if you want to actively prevent unrestrained user-level copying. But if you want to enable copying, you can wrap the array into a struct.

This approach is not terribly elegant, but that's probably the only way to hide implementation when you want to keep objects of your type freely user-definable.