Home > Blockchain >  How to automatically pad bytes in a structure to a specific alignment?
How to automatically pad bytes in a structure to a specific alignment?

Time:07-31

For example, I have the following structure:

typedef struct st
{
    char x1;
    char x2;
    ...
    char y;
}*st_p;

This definition of structure st may vary over time (it is not guaranteed what will be defined inside ... as development goes on).

Is there a way to guarantee that char y is always aligned on – for example – a 256-byte boundary?

I guess the solution is something like adding an array like the following:

typedef struct st
{
    char x1;
    char x2;
    ...
    char padding[keyword];
    char y;
}*st_p;

Is there such a keyword which calculates the total size of all previous members in this structure and which thereby helps resolve the number of bytes to pad?

CodePudding user response:

Since C11, the C language includes the _Alignas attribute,1 with which you can specify a desired (minimum) alignment requirement for any object, including a member of a structure.

So, in your case, you can skip the 'manual' padding and just add that attribute to the char y; declaration:

typedef struct st {
    char x1;
    char x2;
    //...
    _Alignas(256) char y;
}*st_p;

1 However, note that the C Standard does not require that an implementation supports so-called "extended alignment" – that is, an alignment requirement that is greater than that of a max_align_t type (typically 8 or 16 bytes). What it does require, though, is that the specified alignment be a positive power of 2 (which is true, in your case).


As an addendum/alternative, I shall also address your direct question:

Is there such a keyword which calculates the total size of all previous members in this structure and which thereby helps resolve the number of bytes to pad?

The 'keyword' (actually, an operator) that could be used here is sizeof – so long as you put "all previous members" inside an anonymous struct. Here's an example:

#include <stdio.h>
#include <stddef.h>

typedef struct st {
    struct inner {
        char x1;
        char x2;
        char x3[714];
        //...
    };
    char padding[256 - sizeof(struct inner) % 256];
    char y;
}*st_p;

int main()
{
    struct st test;
    test.x1 = 'A'; // You can access the anonymous structure members as though
    test.x2 = 'B'; // they were 'direct' members of the enclosing structure.
    printf("%c %c %zu\n", test.x1, test.x2, offsetof(struct st, y));// Offset is 768
    return 0;
}

But note that, in this code, although the offset of y will be a multiple of 256 bytes, that doesn't guarantee that y will be 256-byte aligned. That will only be true in an instance of the st structure that is itself aligned on a 256-byte boundary … and to ensure that, you will need an alignment attribute on the structure itself.

CodePudding user response:

It is possible to use the compiler attributes to tell it to align a particular structure field to a specific bound. For example, if you are using GCC, you can use:

__attribute__((aligned(n)))

Thus, your example would become:

typedef struct st
{
    char x1;
    char x2;
    ...
    char __attribute__((aligned(256))) y;
}*st_p;

If you have to do this at several places, you can even imagine defining a special type for this, something like:

typedef char __attribute__((aligned(256))) aligned_char;

typedef struct st
{
    char x1;
    char x2;
    ...
    aligned_char y;
}*st_p;

This is not limited to structures field, you can also apply this to local or global variables.

However, keep in mind this may not work with all compilers as the attributes are binded to the compiler and not the C language.

If you are using MSCV, you may be able to replicate the behavior with

__declspec(align(x))

CodePudding user response:

Could use a union, but there is no .padding[] member. Could also use a check that the offset is correct in case the first struct is larger than desired offset.

#define OFFSET 256  /* Does not need to be a power-of-2 */

typedef struct st {
  union  {
    struct {
      char x1;
      char x2;
    };
    struct {
      char dummy[OFFSET];
    };
  };
  char y;
} st;

void bar(void) {
  st o1;
  o1.x1 = '1';
  o1.x2 = '2';
  o1.y = 'y';
  printf("%p\n", (void *) &o1);
  printf("%p\n", (void *) &o1.y);
}

_Static_assert(offsetof(struct st, y) == OFFSET, "TBD code");

Sample output

0xffffcac0
0xffffcbc0

This does not insure the alignment is 256, but that the offset of member y is 256 - which I think is OP's true goal. @Adrian Mole

  • Related