23 April 2011

Strange C sizeof(struct) results?

If you wonder, why sizeof operator returns values bigger than you expect, you probably have to learn about compiler data structure alignment(as I had to:). Here I post a simple program demonstrating the case.

main.c

#include <stdio.h>
#include <string.h>

typedef struct 
#ifdef PACKED 
__attribute__ ((packed)) 
#endif
{
    char *str;      // 8
    char ch ;       // 1
    int a;          // 4
    int b;          // 4
    int c;          // 4
    // Packed total size should be: 21
    // Aligned total size should be: 24
} test_t;

static void print_sizes(test_t *t)
{
    printf("DATA TYPE SIZES\n");
    printf("char*: %ld\n", sizeof(char*));
    printf("char: %ld\n", sizeof(char));
    printf("int: %ld\n", sizeof(int));

    printf("\nSIZE OF *t: %ld\n", sizeof(*t));
}

int main (int argc, char const* argv[]) {
    test_t t;
    t.str = "test string"; 

    print_sizes(&t);

    return 0;
}

makefile

ifeq ($(PACKED), true)
    PACK=-DPACKED
else
    PACK=
endif

ifdef OUT
    OUTFILE=$(OUT)
else
    OUTFILE=test
endif

CC=gcc
CFLAGS=-Wall -c $(PACK)

all: test

test: main.o
    $(CC) main.o -o $(OUT) 

main.o: main.c
    $(CC) $(CFLAGS) main.c -o main.o

clean: 
    rm -f *.o *~

Compile versions with packed and padded memory:

$ make PACKED=true OUT=test_packed
$ make OUT=test_padded

and test them:
$ ./test_packed
DATA TYPE SIZES
char*: 8
char: 1
int: 4

SIZE OF *t: 21

$ ./test_padded
DATA TYPE SIZES
char*: 8
char: 1
int: 4

SIZE OF *t: 24

So one should consider a space-time tradeoff for every particular program.

I'd be glad, if it helps someone.