Memory alignment in C-structs under Windows 32bits - c

Here is a snippet:
struct a {
float* f;
char c;
int i;
char z[4];
double d;
short s;
};
struct b {
struct a a1;
int j;
struct a a2;
};
When I do a printf("%d\n",sizeof(struct a)), it emits to me 32... But when I do the same for the struct b, it emits 72 which I don't know how can be possible this, it should be 32+4+28(padding)+32 following the same calcs that I did to find out the previous result... can anyone tell me why is this happening?

From my calculations, struct a requires 26 bytes (including padding in the middle) + 6 bytes at the end. It looks something like this:
struct a {
float* f; // takes 4 bytes
char c; // takes 1 bytes + 3 padding
int I; // takes 4 bytes
char z[4]; // takes 4 bytes
double d; // takes 8 bytes, sets a requirement for memory alignment
short s; // takes 2 bytes.
// here there are 6 more bytes for padding required for array alignment.
};
The double in the struct means that struct a must be positioned on an 8 byte alignment mark, so that the double is correctly aligned.
Now, when we have struct b, we have:
struct b {
struct a a1; // takes 32 bytes, REQUIRES and 8 byte alignment
int j; // takes 4 bytes + 4 byte padding (for alignment).
struct a a2; // takes 32 bytes, MUST start on an 8 byte alignment
};
I hope this wasn't homework or something... :-p

Nothing is aligned to more than multiples of 8 for the x86/amd64 architectures. See for example Structure Alignment for Visual Studio. struct a and struct b have a double member, so they must be aligned at a multiple of 8 and their sizeof must be a multiple of 8; you can easily see why 32 is correct for struct a. The int j is 4 bytes, at a multiple of 4; since it comes immediately after struct a a1 it need no padding, being placed a multiple of 8. struct a a2 needs to be at a multiple of 8, so 4 bytes of padding are added. Overall, struct b needs 32 bytes for member a1, 4 bytes for member j, 4 bytes of padding (to bring a2 to a multiple of 8) and 32 for member a2 for a total of 72.

Related

What determines the distance between two structure members?

#include‬ <stdio.h>
struct test
{
unsigned int x;
long int y;
unsigned int z;
};
int main()
{
struct test t;
unsigned int *ptr1 = &t.x;
unsigned int *ptr2 = &t.z;
printf("%d", ptr2 - ptr1);
return 0;
}
This program's output is 4 on my system, why do I get this result instead of 2?
Is the ptr2 - ptr1 statement correct as ptr1 and ptr2 come from pointers to members of the same structure item?
The reason this outputs 4 has to do with the size of each type and struct padding and alignment.
On my system, sizeof(unsigned int) is 4, sizeof(long int) is 8, and sizeof(struct test) is 24. So to ensure that the 64-bit field lies on a 64-bit boundary, the structure is physically laid out like this:
struct test
{
unsigned int x; // 4 bytes
// 4 bytes padding
long int y; // 8 bytes
unsigned int z; // 4 bytes
// 4 bytes padding
};
So when you take the difference between the offset of x and the offset of z, there are 16 bytes difference. And since we're doing pointer subtraction, the value of the difference is {byte offset difference} / {element size}. So we have 16 (byte difference) / 4 (sizeof(unsigned int)) == 4.
If sizeof(long int) was 4, then the struct would probably be laid out like this:
struct test
{
unsigned int x; // 4 bytes
long int y; // 4 bytes
unsigned int z; // 4 bytes
};
In which case the output would be 2.
Note that while the ordering of struct members is defined to be sequential, the layout of the padding is is implementation defined. Compilers are free to pad as they see fit.
From section 6.7.2.1 of the C standard:
13 Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that
increase in the order in which they are declared. A pointer to a
structure object, suitably converted, points to its initial
member (or if that member is a bit-field, then to the unit
in which it resides), and vice versa. There may be unnamed
padding within a structure object, but not at its beginning.
...
15 There may be unnamed padding at the end of a structure or union.

sizeof struct less than 4 B is reported actual [duplicate]

This question already has answers here:
Why is padding added for multiple data members of structures and not for single members?
(4 answers)
Why isn't sizeof for a struct equal to the sum of sizeof of each member?
(13 answers)
Closed 8 years ago.
Am trying to understanding the struct padding.
The below struct is padded:
struct s {
int j;
char c;
int i;
};
==> sizeof(struct s) = 12
But for this struct it is not padding. why?
struct s {
char c;
}
==> sizeof(struct s) = 1
OR
struct s {
short int i;
}
==> sizeof(struct s) = 2
Why the padding is not applicable for the above two structs?
Padding is done to keep members of the struct aligned, so that access is fast.(*) Consider what happens in an array of structs:
struct s {
int i;
char c;
};
struct s a[0];
If this struct were not padded, a[1] would have the address (char *)a + 5. That's unaligned, assuming a[0] is aligned. Therefore, the struct will typically be padded to a multiple of sizeof(int). (Were i a long long, then the whole struct would be padded to a multiple of sizeof(long long); try and see.)
With a single char, there's no need to pad because the char will be aligned anyway, while there are no other members that become unaligned. With a single short, an alignment of 2 is sufficient to keep the single member aligned, always.
(*) On some CPUs, but not Intel x86-compatible ones, unaligned access can actually crash your program.
The padding is added to make sure that the int member i is aligned.
Assuming that your int is 4 bytes in size, then it will be placed on a 4 byte boundary to align it. That means that there are 3 bytes of padding after the char. The size of 12 is therefore quite reasonable.
Imagine if there was no padding. Then the offsets would be:
Member Offset
j 0
c 4
i 5
If the struct was laid out this way then i would be mis-aligned. To place it on a 4 byte boundary, it needs to be at offset 8. Hence the 3 bytes of padding, and the total size of 12. So, the actual layout is:
Member Offset
j 0
c 4
<padding> 5
i 8

Size of a struct with union and bitfields

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.
So you have a lot of questions in here. I'll answer some as I go:
sizeof struct is zero?
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;
};
Bitfield layouts
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.
sizeof wasn't rounded up to 12?
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.
Recommendations
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.
Padding can occur though:
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)
};

Packed bit fields in c structures - GCC

I am working with structs in c on linux.
I started using bit fields and the "packed" attribute and I came across a wierd behavior:
struct __attribute__((packed)) {
int a:12;
int b:32;
int c:4;
} t1;
struct __attribute__((packed)) {
int a:12;
int b;
int c:4;
}t2;
void main()
{
printf("%d\n",sizeof(t1)); //output - 6
printf("%d\n",sizeof(t2)); //output - 7
}
How come both structures - that are exactly the same - take diffrent number of bytes?
Your structures are not "exactly the same". Your first one has three consecutive bit-fields, the second has one bit-field, an (non bit-field) int, and then a second bit-field.
This is significant: consecutive (non-zero width) bit-fields are merged into a single memory location, while a bit-field followed by a non-bit-field are distinct memory locations.
Your first structure has a single memory location, your second has three. You can take the address of the b member in your second struct, not in your first. Accesses to the b member don't race with accesses the a or c in your second struct, but they do in your first.
Having a non-bit-field (or a zero-length bit-field) right after a bit-field member "closes" it in a sense, what follows will be a different/independent memory location/object. The compiler cannot "pack" your b member inside the bit-field like it does in the first struct.
struct t1 // 6 bytes
{
int a:12; // 0:11
int b:32; // 12:43
int c:4; // 44:47
}__attribute__((packed));
struct t1 // 7 bytes
{
int a:12; // 0:11
int b; // 16:47
int c:4; // 48:51
}__attribute__((packed));
The regular int b must be aligned to a byte boundary. So there is padding before it. If you put c right next to a this padding will no longer be necessary. You should probably do this, as accessing non-byte-aligned integers like int b:32 is slow.

Data padding on a 64 bit system discrepancy

This program creates and measures a struct with a pointer (8 bytes) and 3 ints (4 bytes each) and shows there are 4 bytes of data padding.
I don't understand why there are 4 bytes of data padding, either the CPU handles it 8 bytes at a time and there should be another 8 bytes of padding or it handles it 4 bytes at a time and there should be none right?
Or does it stick 2 4 byte values in an 8 byte section of memory and let the CPU split it up at runtime? (This would explain the discrepancy but it seems a bit inefficient to me)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct test {
char *name;
int age;
int height;
int weight;
};
struct test *create(char *name, int age, int height, int weight)
{
struct test *thing = malloc(sizeof(struct test));
thing->name = strdup(name);
thing->age = age;
thing->height = height;
thing->weight = weight;
return thing;
}
void destroy(struct test *thing)
{
free(thing->name);
free(thing);
}
int main(int argc, char *argv[])
{
struct test * t1 = create("bleh",1,2,3);
printf("Sizeof struct: %lu\n",sizeof(struct test));
printf("Sizeof pointer (On 64bit system): %lu\n",sizeof(char *));
printf("Sizeof int: %lu\n",sizeof(int));
destroy(t1);
return 0;
}
Output:
Sizeof struct: 24
Sizeof pointer (On 64bit system): 8
Sizeof int: 4
The entire struct is probably padded at the end, for alignment reasons. This is needed since you might want to have an array of this struct.
The padding you mention makes the struct always end up on an address which is evenly divisible by 8.
The pointer presumably needs to be aligned on 8 bytes. Think about what happens when you form an array of your class, test a[10]. The only way to ensure that a[i].name is aligned on 8 bytes is by padding the class to a multiple of 8 bytes.

Resources