Data padding on a 64 bit system discrepancy - c

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.

Related

Why structure and its typedef consume different size when aligned?

I was expecting both sizes are 8 but i get sizeof(myStruct) = 16, sizeof(myType) = 8. I compiled this on Windows 64-bit machine with MinGW.
#include <stdio.h>
#include <stdint.h>
struct s1{
int8_t a;
int32_t b;
} __attribute__((aligned));
typedef struct{
int8_t a;
int32_t b;
}s2 __attribute__((aligned));
struct s1 myStruct;
s2 myType;
int main(int argc, char **argv)
{
printf("sizeof(myStruct) = %zu, sizeof(myType) = %zu\n", sizeof(myStruct), sizeof(myType));
return 0;
}
struct s1 { … } __attribute__((aligned)); says the members of struct s1 should be aligned to the “maximum alignment” for the target, which is apparently 8 bytes. So each member is put at a multiple of 8 bytes, making the whole structure 16 bytes. (The GCC documentation on this fails to state that specifying this attribute for the structure affects its members, but that appears to be the case.)
typedef struct { … } s2 __attribute__((aligned)); says s2 is a structure with ordinary alignment requirements, so its b member is put at a multiple of 4 bytes and the total size is 8 bytes, and then the s2 type should be aligned to the “maximum alignment”. Thus, when s2 objects are created, they will be put at locations that are multiples of 8, but the layout of members within them will not change.
To make the structure defined with the typedef have the same layout as struct s1, you can use typedef struct { … } __attribute__((aligned)) s2;.

Memory alignment in C-structs under Windows 32bits

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.

Why can't we access bits that we pad in structures?

My question is we do padding to align structures.
typedef struct structb_tag
{
char c;
int i;
} structb_t;
Here we use 8 bytes. Why can't we use the 3 bytes that lot?
Why cant we use the 3 bytes
You could.
To do so measure the size your implementation allocates for a struct and then make it a union adding a char-array of exactly the size measured and there you go.
Assuming this
typedef struct structb_tag
{
char c;
int i;
} structb_t;
is created using eight bytes, that is sizeof (structb_t) evaluates to 8, change it to the following
typedef union unionb_tag
{
char bytes[8];
struct
{
char c;
int i;
} structb;
}
More reliable, in terms of portability and also robustness, would be this:
typedef union unionb_tag
{
struct structb_tag
{
char c;
int i;
} structb;
char bytes[sizeof (struct structb_tag)];
}
If you are using GCC and space is the most important thing for you instead of speed (which padding provides) you could just request the compiler to not do the padding, struct __attribute__((__packed__)) mystruct, padding is the way for compiler to align structures in the natural for faster access.
You can always take the pointer to the structure convert it to a byte pointer and access any byte of that structure.This is dangerous way, though.
The padding are implementation dependent, which are not defined by the standard, you cannot not use them as there is no way to reference the padding bytes.
Yes, you can.
typedef struct structb_tag
{
char c;
char pad[3];
int i;
} structb_t;
structb_t test;
test.pad[0] = 'a';
In short, we can use that three bytes.
The reason why we need 3 bytes padding is for memory usage optimization, so the compiler will help us add an gap between c and i. So when you use
typedef struct structb_tag
{
char c;
int i;
} structb_t;
It actually
typedef struct structb_tag
{
char c;
char[3] unseen_members;
int i;
} structb_t;
Accessing these unseen members will not cause any segmentation fault. In the point of view of OS, there's no difference between accessing members declared by programmers explicitly and declared by compiler implicitly.
#include <stdio.h>
#include <string.h>
typedef struct Test {
char c;
int i;
} MyTest;
int main() {
MyTest my_test;
memset(&my_test, 0, sizeof(my_test));
my_test.c = 1;
int* int_ptr = (int *)&my_test.c;
printf("Size of my_test is %lu\n", sizeof(my_test));
printf("Value of my_test.c(char) is %d\n", my_test.c);
printf("Value of my_test.c(int) is %d\n", *int_ptr);
return 0;
}
This gives:
Size of my_test is 8
Value of my_test.c(char) is 1
Value of my_test.c(int) is 1
We can access any byte in the structure using a pointer to that structure and typecasting that pointer to (char *) if we accordingly increment that pointer then we can access any byte but this not good programming skill. Structures are padded with some extra bytes so that an execution of the program can become faster.

Explanation for the size of structs in C?

So I'm looking at this code:
#include <stdio.h>
struct Student {
int id;
char name[32];
} s, *sp;
int main() {
printf("sizeof(structStudent) = %u\n", sizeof(structStudent));
printf("sizeof(s) = %u\n", sizeof(s));
printf("sizeof(structStudent*) = %u\n", sizeof(structStudent*));
printf("sizeof(sp) = %u\n", sizeof(sp));
return 0;
}
The output is the following:
sizeof(struct Student) = 36
sizeof(s) = 36
sizeof(struct Student*) = 4
sizeof(sp) = 4
Why is the size of struct Student* 4 and why is the size of sp also 4? My powerpoint does not elaborate on this. I know why the size of struct Student and s is 36: because 32 char bytes+4 bytes(for one int)=36 total.
struct Student * is a pointer and it doesn't contain almost any data, it's merely a pointer. But pointers are stored somewhere and take some space, 4 bytes in your case.
struct Student, however, is a fully-featured struct that occupies as much space as you've calculated (the array and the id take their space).
On your platform, simple pointers occupy 32 bits. That's basically the definition of a 32-bit platform.
The address of the White House doesn't have to be longer than my address just because the White House is bigger than my house.

Declaring multiple structs and overlaying them on already allocated memory

I am very new to C/C++, so I know that this question is probably trivial but I don't understand how to proceed. I have allocated blocks of memory that are 512 bytes each like so (Sector is a struct of size 512 bytes):
char* block = (char *) malloc (sizeof(Sector));
I have another struct that is 128 bytes in size:
typedef struct inode {
int fileSize;
int fileType;
int* blockPointer[30];
} inodeFile;
What I want to do is overlay this struct on the block. I need each block to contain 4 inode structs, but each struct may not have any values associated with it until later on in the program. So for example:
((*inodeFile) block)->fileSize = 10;
If I am understanding correctly, this is setting the first 4 bytes of the pointer block to fileSize. I would continue to do this for each field of the struct.
My question is, how can I do this for 4 different inodes? And since there are 4 different inodes, how can I return the values of each field for the different structs? It seems like simply saying block->fileSize wouldn't work because there can be up to four different file sizes.
You can use a union to overlay the blocks on the sectors. Because the fields are of int type or pointer or size 512 there shouldn't be an alignment problem so long as the natural size is 32-bit.
typedef struct {
int fileSize;
int fileType;
int* blockPointer[30];
} inode;
typedef union {
unsigned char bytes[512];
inode block[4];
} sector;
int main()
{
sector thisec;
thisec.bytes[511] = 0;
thisec.block[0].fileSize = 10;
return 0;
}

Resources