How to deal with alignment skew when storing a structure in a byte buffer?

620 views Asked by At

I want to refer to a memory location as either an array of chars or a specialized struct with two upfront char members. The reason for this is a C-API that only takes a char array, but I want to put some more information into it with my struct that I can then read out based on whether the first character is a special character (e.g. "@") or not.

struct some_struct {
   char a;
   char b;
   void* some_ptr;
}

However here's the problem: As far as I know, char arrays are not padded. Structs however are aligned by the size of their largest member according to this topic. When I want to refer to the first two chars by either the struct or the char array, it doesn't add up:

Front padded struct compared to char

Am I right to assume this is how the struct is aligned compared to the array (4 byte alignement)?. If so, how can I remove the unwanted front padding so that the first two chars of the struct line up with the char array? The rest of the struct can be default aligned to 4 byte boundaries, because I do not want to #pragma pack(1) the whole thing.

EDIT: Here's my intended usage:

  • Create struct some_struct
  • reinterpret_cast it to const char *
  • pass it to C API as a const char *
1

There are 1 answers

5
user3840170 On

I think the simplest way to accomplish what you (seem to) want is to incorporate the prefix intrusively into your data structure. In other words, declare it the following way:

struct some_struct {
    char magic;  /* must be '@' */
    char a;
    char b;
    void *some_ptr;
};

and then do this to actually initialize it:

#include <new> // for placement new

alignas(some_struct) char buffer[SIZE];
static_assert(sizeof(buffer) >= sizeof(some_struct));

auto mystruct = new (buffer) some_struct;
mystruct->magic = '@';
/* fill the other fields of *mystruct */

The resulting memory layout will be this:

buffer:
┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬╌╌╌
│  [0]  │  [1]  │  [2]  │  [3]  │  [4]  │  [5]  │  [6]  │  [7]  │
└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴╌╌╌

*mystruct:
┌───────┬───────┬───────┬───────┬───────────────────────────────┐
│ magic │   a   │   b   │ (pad) │            some_ptr           │
└───────┴───────┴───────┴───────┴───────────────────────────────┘

making &mystruct->some_ptr well-aligned, as long as buffer is sufficiently aligned to store a some_struct.