2

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 *
16
  • What's your struct declaration? Is it just two char members? Commented Apr 12, 2022 at 6:29
  • 2
    You use C or C++? Decide. Commented Apr 12, 2022 at 6:29
  • 1
    The issue of aligning occurs when you allocate. When you have an array of chars, they are not your struct. When you allocate a struct, it's not an array of chars. Commented Apr 12, 2022 at 6:30
  • It looks more like a struct is allocated on an even address, whereas the char array on any address. That would not bode well. Commented Apr 12, 2022 at 6:31
  • 3
    There shouldn't be any padding at the beginning. stackoverflow.com/questions/55560382/… stackoverflow.com/questions/8864311/… Commented Apr 12, 2022 at 6:31

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

In your answer you align the char array to some_struct's boundaries. Could you do the opposite and createsome_struct aligned to char boundaries like alignas(char) some_struct mystruct; ? Am I correct that this would also get rid of first member alignement requirement?
A structure is always aligned to char boundaries, because char has an alignment requirement of 1, which everything trivially satisfies. If you want to set the alignment requirement of some_struct to 1 (to make it storable in any byte buffer), there is no standard way to do that, but you can apply a packing pragma (like you mentioned) or an attribute like [[gnu::packed]]. Beware of UB in that case, however.
Alright thanks. I have to get used to the right terminology it seems. Yes, the alignement requirement of the struct should be 1 byte but the padding should not be affected such as in [[gnu::packed]]. But I guess that's asking for too much. I figured I could also just reinterpret cast the struct to char and then it will automatically fullfill alignements of the struct.
auto mystruct = reinterpret_cast<some_struct *>(buffer); is a strict aliasing violation and therefore undefined behavior. Seems as if the details of the C api in question might be troublesome.
@AndrewHenle Not quite, character pointers are allowed to alias pointers to other objects just fine. (It’s how memcpy manages not to be instant UB.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.