Search code examples
cstructsizeofmemory-alignmentstruct-member-alignment

Why Offset varies for character array in C structure if array size changes and how the defined macro is calculating offset here?


I have defined a macro that calculates the offset of a structure to any of the structure field. The Code is as follow:

#define offset(struct_name, fld_name) \
(unsigned int)&(((struct_name *)0)->fld_name)

typedef struct emp_{
   char name[20];
   unsigned int salary;
   char designation[30];
   unsigned int emp_id;
} emp_t;

int main(int argc, char **argv){
    unsigned int offsetValue;
    offsetValue=offset(emp_t,salary);
    printf("field = %s\n","salary");
    printf("offset = %d\n", offsetValue);
    return 0;
}

If I compile and run the code the offset for field "salary" is 20 and it should be 20. But if I change structure field char name[20]; to char name[30]; the offset for "salary" changes to 32 but it should be 30. if I further change structure field to char name[1]; the offset for "salary" changes to 4 but it should be 1. Why these offset value discrepancies are happening?

The second part of the question is how exactly the #define offset macro is calculating the offset? What is &(((struct_name *)0)->fld_name) actually doing? The outer & denote the address but what exactly remaining (((struct_name *)0)->fld_name) means?


Solution

  • There is used aligning for objects of the type unsigned int that in your system have the size of 4 bytes. 30 is not divisible by 4. So two bytes are appended to the character array.

    Consider the following demonstrative program.

    #include <stdio.h>
    
    int main(void) 
    {
        printf( "sizeof( struct A ) = %zu\n", sizeof( struct A { char c; int x; } ) );
        printf( "sizeof( struct B ) = %zu\n", sizeof( struct B { char c; double d; } ) );
    
        return 0;
    }
    

    Its output is

    sizeof( struct A ) = 8
    sizeof( struct B ) = 16
    

    The type int has the size equal to 4 and the type double equal to 8. So an object of the type struct A shall be aligned by the bound divisible by 4 and an object of the struct B shall be aligned by the bound divisible by 8.

    You for example can pack structures using compiler directives. But in this case access to data members of such structures will be inefficient.