Avoid populating the structure in c using the __ attribute __ ((packed))

I use __attribute__((packed)) to avoid filling the string. The following code works fine, but when I add another int member inside the structure, the compiler populates my structure.

 #include <stdio.h> struct test { int x; char c1; char c2; char c3; char c4; char c5; // int d; Pads if I uncomment } __attribute__((packed)) obj = {50,'X','Y','Z','A','B'}; int main () { struct test *ptr= &obj; char *ind = (char *) &obj; printf("\nLet see what is the address of obj %d", ptr); printf("\n Size of obj is : %d bytes ", sizeof(obj)); printf("\nAddress of x is %d", &ptr->x); printf("\nAddress of c1 is %d", &ptr->c1); printf("\nAddress of c2 is %d", &ptr->c2); printf("\nValue of x is %d", ptr->x); printf("\nAddress of x is %c", ptr->c1); printf("\nFetching value of c4 through offset %c", *(ind+7)); } 

The above code works as expected, and the size of obj is 9 bytes (it had 12 bytes to populate).

However, when I uncomment the int d in my structure, the code outputs:

Obj size: 16 bytes

instead of the expected 13 (9 + 4) bytes.

What's wrong?

+8
c struct
source share
2 answers

Structures have two types of padding. (1) An additive has been added to make the structure a multiple of a certain number (in your case, the size is int ); and (2) An additive has been added to place certain types of data at an address divisible by a certain number. For example, 4 bytes for int . Therefore, in your case, when the compiler is happy to delete the first type of padding, I think that it still forces the member int d to the address divisible by 4. Since there are 5 characters before d , an addition of 3 bytes is added to force d to the address divisible by 4.

Try moving the int d element over the characters. Then, of course, you have to change the offset used in fetching value of c4 through offset . You can even put it right above c5 . Then you do not have to change the line fetching value of c4 through offset . Example:

 struct test { int x; int d; char c1; char c2; char c3; char c4; char c5; } __attribute__((packed)) obj = {50,'X','Y','Z','A','B'}; 

OR

 struct test { int x; char c1; char c2; char c3; char c4; int d; char c5; } __attribute__((packed)) obj = {50,'X','Y','Z','A','B'}; 
+1
source share

Thanks to everyone who took the time to study the features. I would like to talk about the behavior of the compiler that I use after performing various checks, and I would like to adhere to the fact that in both scenarios, ie, with and without the compiler, it requires the integer member to fall at an address that is divided by its size, in this a case of 4 bytes (spaces between them), which, although they do not define β€œattribute use,” nevertheless serve a good purpose. As we know, and I assume that the compiler rightfully focuses more on speed rather than space, and therefore wants to save time on executing instructions and saving the machine cycle. Strictly Following the above protocol, if the compiler assumes that the next member it encounters is an integer, then this is the best condition, because then the compiler will not have to worry about complementing or missing the complement because the next integer will definitely fall to the address, divisible by 4 (bytes). Even better, if double is 4 bytes in size, as in the 32-bit linux arch. One thing I can assure is that if there is no padding (using the attribute) the compiler avoids the padding at the end, but if padding is done in bytes of intermediate elements, as well as at the end, to make the size of the whole structure divided by 4. (since the size of the structure, which is divided by 8 (double size on some machine), is also divided by 4). Since the question and the operation is completely compiler-based it was dishonest for everyone, why thanks even more.

0
source share

All Articles