Matthew Darnell
Matthew Darnell

Reputation: 1365

How to correctly align structs in C using posix_memalign?

I know that there have been many questions about this topic, but I still find myself confused.

I have written this simple program to help me visualize memory alignment in C:

#include <stdio.h>
#include <stdlib.h>
struct S{
  int a;    
  short b;
  char c;
};
int main()
{
    struct S *s;
    posix_memalign((void**)&s, 8, 12) == 0 ? printf("allocation successful"):printf("allocation failed");
    printf("\nlocation of struct:\t%p\n", s);
    printf("\nlocation of int:\t%p\nlocation of short:\t%p\nlocation of char:\t%p\n", &(s->a), &(s->b), &(s->c));
    printf("\nsizeof struct: %lu\n", sizeof(s));
    free(s);
    return 0;
}

This is working well, but I am getting confused with the alignments.

Using these arguments (alignment=8 bytes, size=12):

allocation successful
location of struct: 0x205e010

location of int:    0x205e010
location of short:  0x205e014
location of char:   0x205e016

sizeof struct: 8

The int is the largest element of the struct, at 4 bytes. I can see here that the short begins 4 bytes later, and the char 2 bytes after that. Why isn't there another 2 bytes of padding between the short and char?

Also, why does the allocation fail if I use an alignment of 4 bytes? Since that is the size of the largest element in the struct, shouldn't it work?

allocation failed
location of struct: (nil)

location of int:    (nil)
location of short:  0x4
location of char:   0x6

sizeof struct: 8

Upvotes: 1

Views: 874

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 755006

The char member can be aligned on any byte boundary; there is never a need to insert padding before a char member, even though a compiler could if it wanted to. The way it is laid out, there is just a single padding byte in the structure. If there was a gap after the short member, the structure would have five bytes of padding, which is wasteful.

The chances are that the minimum alignment that posix_memalign() supports is 8 on your machine. POSIX says it can fail:

[EINVAL] The value of the alignment parameter is not a power of two multiple of sizeof(void *).

Having said that, it looks like sizeof(void *) is probably 4 (the addresses you print fit in a 32-bit address space). Maybe you should print errno (and/or strerror(errno)) to see what the cause of failure is.

Upvotes: 1

Related Questions