Tuesday, February 2, 2010

The alignment magic

We faced some trouble with assignment of memory to some structures. We did an mmap and allocated memory to different variables and structures. These variables and structures were defined in random order. There were some variables and some structures followed. This caused the problem of memory alignment. So, today, I did a bit of reading on memory alignment and the program that you see below is the result of that reading.

#include <stdio.h>

typedef struct {
    unsigned char uc;
}TST1;

typedef struct {
    unsigned char uc;
    unsigned short us;
}TST2;

typedef struct {
    unsigned char uc;
    unsigned short us;
    unsigned int ui;
}TST3;

typedef struct {
    unsigned char uc;
    unsigned short us;
    unsigned int ui;
} TST4 __attribute__ ((aligned(2)));

#define PRN_ALIGN(x) printf("Alignment of %s is %d \n",#x, __alignof__ (x))

int main()

{

    PRN_ALIGN(TST1);
    PRN_ALIGN(TST2);
    PRN_ALIGN(TST3);
    PRN_ALIGN(TST4);

    return 0;
}

You can clearly see that the alignment varies for different structures. The way to find alignment is to use the __alignof__ (datatype). However, gcc allows you to force the alignment to be something other than the default value. That is achieved by the __attribute__ ((aligned(AlignmentValue))).

We solved our problem by re-arranging the variables. This caused the structure to appear exactly at the alignment boundary. The other solutions would have been to force all structures to have alignment of 1. Yet another solution would have been to do use the __alignof__ to find the acceptable location for placing the structure. Below code is an example using malloc

    unsigned char *memPtr;
    
    memPtr=malloc(100);

    printf("%p\n",memPtr);
    TST2 *pstMyStructure= (TST2*) (((int)memPtr / __alignof__ (TST2) + 1) * __alignof__ (TST2));
    printf("%p\n",pstMyStructure);
    memPtr = (unsigned char*)((int)memPtr / __alignof__ (TST2) + 1) + __alignof__ (TST2) + sizeof(TST2);
    printf("%p\n",memPtr);

(Do keep in mind that strictly speaking, we cannot interchange integers and pointers)