-2

According to c_faq,

typedef struct  {
    char a[3];
    short int b;
    long int c;
    char d[3];
} T;

sizeof(T) will return me 16 on a 32-bit gcc compiler. Because the alignment is 4, so to calculate, I should do this: 3+(1)+2+(2)+4+3+(1), where the brackets represent paddings. GCC concurs.

Based on that logic, did some practices on my own with another question.

typedef struct{
    char buf1[9];
    unsigned short s;
    double d;
    char buf2[3];
} S;

sizeof(S) should return me 32 on a 32-bit gcc compiler. Because the alignment is 8, so to calculate, I should do this: 8+1+2+(5)+8+3+(5). However, gcc is telling me that sizeof(S) is 24.

I reckoned it's because of optimization, however, after messing with the -O0 flag in gcc, sizeof(S) still results in 24.

I was using gcc -m32 main.c to compile.

What is going on here?

If I understood properly, the reason why my calculation and GCC's calculation do not match is because each compiler has their own way of handling struct data. Then what is a universal way of calculating the size of a struct? Or rather, what is the original way of calculating the size of a struct?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Jieqin
  • 588
  • 5
  • 21
  • 2
    Your wording is confused: you say GCC gives sizeof(S) as 24, but then you say "sizeof(S) still results in 32". I think your question is invalid and you have simply confused yourself. – John Zwinck Dec 12 '16 at 04:02
  • 4
    Overt use of [`offsetof`](http://en.cppreference.com/w/c/types/offsetof) and some simple output statements will probably hint some answers for you. I think the padding following `S::buf1` may surprise you. – WhozCraig Dec 12 '16 at 04:06
  • 1
    I'm not following how you're getting `8+1+2+(5)+8+3+(5)`. Shouldn't you mean `9+(1)+2+(4)+8+3+(5)`? They both sum to 32, but the implications of structure layout and padding is different. – Cornstalks Dec 12 '16 at 04:09
  • Hi @JohnZwinck, Sorry, my English isn't very good. What I'm trying to say is, when I manually calculated the sizeof struct, it sometimes doesn't tally with the size gcc prints out. – Jieqin Dec 12 '16 at 04:11
  • @Cornstalks I'm trying to group all the data into chunks of 8 because the alignment is 8. I think it's just the way of looking at things, but we talking about the same thing. However, GCC returns 24 for the sizeof(S). – Jieqin Dec 12 '16 at 04:13
  • @Jieqin: Then why in your question do you say " the sizeof(S) still results in 32."? – John Zwinck Dec 12 '16 at 04:13
  • @Jieqin: the FAQ you referenced *does not* say that GCC or any other compiler will lay out the struct as you describe, nor produce the resulting size you specify. A C implementation *might* use that layout, or might choose a different one -- the language gives implementations great freedom in how they lay out structures. The FAQ explains why structures may be laid out with padding, but it does not promise that they *will* be padded under any particular combination of circumstances. – John Bollinger Dec 12 '16 at 04:18
  • 2
    [You might be interested in this question](http://stackoverflow.com/questions/11108328/double-alignment). Notably, on x86, GCC will align `double` on a 4-byte boundary by default, not 8. – Cornstalks Dec 12 '16 at 04:21
  • @JohnBollinger You're right... But how should I calculate the size of a struct, and how do I check whether I've calculated the size correctly? – Jieqin Dec 12 '16 at 04:22
  • 2
    @Jieqin, generally speaking, *you don't* manually calculate the size of a struct. You rely on `sizeof` to determine the size where you need it. It is rarely important to be able to predict the result of `sizeof`. – John Bollinger Dec 12 '16 at 04:25
  • @JohnBollinger :/ My lecturer told me that as well, that different compilers might result in a different size of each struct. However, My final paper requires me to know how the size of each struct is calculated. That question above is from a practice paper given to me where I do not have the answers to... – Jieqin Dec 12 '16 at 04:31
  • 1
    @WhozCraig Thanks for the tip on using *offsetof*! I've been wondering how gcc calculates struct and the padding it's being used. With that *offsetof* function, I am able to find out that the way gcc calculates S is 9+(1)+2+8+3+(1)! I'm not too sure why did gcc pad a 1 to buf1 tho... Could it be because it needs to maintain an even number? – Jieqin Dec 12 '16 at 04:36
  • 2
    @Jieqin: There's 1 byte of padding after `buf1` because `s` needs to be aligned on a 2-byte boundary. `short`s are typically aligned on a 2-byte boundary. – Cornstalks Dec 12 '16 at 04:38
  • @Jieqin structs need trailing padding so that if there is an array of structs, then the next member of the array is correctly aligned. (Arrays are not allowed to have padding between elements) – M.M Dec 12 '16 at 05:02

2 Answers2

4

Then what is a universal way of calculating the size of a struct? Or rather, what is the original way of calculating the size of a struct?

There is no universal way. Nor is there a real "original" way, given that C was created in 1970s, back when PDP-11s were a thing, and C wasn't formally specified until 1989. It's implementation defined, and varies from platform to platform (and I'm not just being flippant; it really truly does vary between platforms and implementations (and even compiler flags!)).

If your professor wants you to compute the size of a structure, then he or she must provide the alignment required for each data type. If they do not, then their question is underspecified (and a virtually infinite number of different answers could be defended as "correct").

Cornstalks
  • 37,137
  • 18
  • 79
  • 144
0

I made the following piece of code to check out the addresses of each element in the struct.

#include <stdio.h>

typedef struct{
    char buf1[9];
    unsigned short s;
    double d;
    char buf2[3];
} S;

int  main()
{
    S S1;
    S *Sptr = &S1;
    printf ("\n sizeof (S) is %d",sizeof(S));
    printf ("\n Buf1 --> %d",(char*) &(Sptr->buf1[0]) - (char*)Sptr);
    printf ("\n s    --> %d",(char*) &(Sptr->s) - (char*)Sptr);
    printf ("\n d    --> %d",(char*) &(Sptr->d) - (char*)Sptr);
    printf ("\n Buf2 --> %d",(char*) &(Sptr->buf2[0]) - (char*)Sptr);
    return 0;
}

The results on my compiler (cygwin 64 bit) were

sizeof (S) is 32
Buf1 --> 0
s    --> 10
d    --> 16
Buf2 --> 24

The short is at byte 10, so it is aligned on 2 byte boundaries. The double is at 16m and is aligned at 8 byte boundaries. The final struct is also padded to 8 bytes.

Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31