Search code examples
cmemory-managementstructalloca

Is it a good practice to hide structure definition in C?


In my opinion, hiding the definition of a structure in C generally makes code safer, as you enforce—with the help of the compiler—that no member of the structure can be accessed directly.

However, it has a downside in that a user of the structure cannot declare variables of its type to be put on the stack, because the size of the structure becomes unavailable this way (and, therefore, the user has to resort to allocating on the heap via malloc() even when it is undesirable).

This can be (partially) solved via the alloca(3) function that is present in all major libc implementations, even though it does not conform to POSIX.

Keeping these pros and cons in mind, can such design be considered good in general?

In lib.h:

struct foo;
extern size_t foo_size;
int foo_get_bar(struct foo *);

In lib.c:

struct foo {
  int bar;
};

size_t foo_size = sizeof foo;

int foo_get_bar(struct foo *foo)
{
  return foo->bar;
}

In example.c:

#include "lib.h"

int bar(void)
{
  struct foo *foo = alloca(foo_size);
  foo_init(foo);
  return foo_get_bar(foo);
}

Solution

  • Yes, it is a good practice to hide data.

    As an alternate to the alloca(foo_size); pattern, one can declare an aligned character array and perform a pointer conversion. The pointer conversion is not fully portable, though. The character array needs to be a VLA, if the size is defined by a variable and not a compile-time constant:

    extern size_t size;
    
    struct sfoo;
    
    #include <stddef.h>
    
    int main(void) {
      unsigned char _Alignas (max_align_t) cptr[size];
      // or unsigned char _Alignas (_Complex  long double) cptr[size];  // some widest type
      struct sfoo *sfooptr = (struct sfoo *) cptr;
      ...
    

    If VLAs are not desired or available, declare the size as a constant (#define foo_N 100) that is guaranteed to be at least as much as needed.