Reputation: 308
I'm trying to count the size in bytes of this struct and have a couple of questions
struct stc {
int a;
int b;
char c;
union stc2 {
long a0;
int a1;
int a2;
};
char arr[10];
int z:2;
};
I'm checking the size in this way:
int main(void) {
printf("%zu\n", sizeof(struct stc));
}
and compile with:
gcc -std=c99 -m32 -Wall -Wextra test.c
It's gcc 4.9 and I'm on 64-bit computer but first want to try with 32-bit values so -m32. Now, the result is 20
, but I've no idea why is that. This is how I'm counting.
struct stc {
int a; // +4 = 4
int b; // +4 = 8
char c; // +1 but next is long, so +4 (alignment) = 12
union stc2 {
long a0; // +4 = 16
int a1;
int a2;
};
char arr[10]; // +8 (for arr[8]) and 2 bits left = 24 (or 28)
int z:2; // +4 = 28 (or 32)
// I'm not sure how it'll work with 2 bits left from char array and
// 2 bits from int, so that why I count 2 different values.
};
This was strange so I tried to figure this out and I know that this union seem to be size 0.
struct stc {
union stc2 {
long a0;
int a1;
int a2;
};
sizeof(struct stc) == 0
. I think that is because of compiler optimization? If so, how to turn it off? If not, why is that?
Another question is of course how to count the size of this struct properly (with or without optimization) and why the size of this simple struct:
struct stc {
char arr[10];
};
is 10 not a 12. I've thought that every value is aligned to 4,8,12,16,20 etc if you won't say to compiler to not align values.
Upvotes: 3
Views: 426
Reputation: 82026
So you have a lot of questions in here. I'll answer some as I go:
You gave the code:
struct stc {
union stc2 {
long a0;
int a1;
int a2;
};
};
Note that you declared no variables inside the struct. You probably meant to do the following, which will likely have the same size as sizeof(long)
.
struct stc {
union stc2 {
long a0;
int a1;
int a2;
} x;
};
So, let's try to figure out where 20
comes from. First, let's rerwite the type without the union
that isn't doing anything (see previous heading).
Also, note that structs with bitfields are not required to be laid out in memory the same way as normal types. But let's make some guesses anyways.
struct stc {
int a; // Offset 0, Size 4
int b; // Offset 4, Size 4
char c; // Offset 8, Size 1
char arr[10]; // Offset 9, Size 10
int z:2; // Offset 19, Size 1-ish
};
So it seems to fit fine.
struct stc {
char arr[10];
};
So, each type has a size and an alignment requirement. For char
, both of these are 1. For uint32_t
, they are usually both 4. But depending on the architecture, the alignment could be different.
So in this case, the maximum alignment needs of any element of the struct stc
is 1. So the alignment requirements of the entire struct is still 1
, even though the size is 10
.
Generally speaking, you want to add whatever padding is necessary to the size such that the declaration struct stc x[2]
would cause all of the elements to be properly aligned.
So, there are a few things that you could do here to help learn what your compiler is doing.
When posting questions about memory layout on stack overflow, it's very helpful to use the types defined in stdint.h
. These include types like int32_t
and int16_t
. These are nicer because there is no confusion on what size a long
is.
You can use the offsetof tool to determine where a compiler is placing the members. You can learn some more about how to use it here.
Here's a pretty simple example of a struct with a good bit of padding that the compiler would have to insert.
struct x {
uint64_t x; // Offset 0, Size 8
char y; // Offset 8, Size 1
// Offset 9, Size 1 (Padding)
uint16_t z; // Offset 10, Size 2
// Offset 12, Size 4 (Padding)
};
Upvotes: 5