4.11 The __packed__ Attribute This attribute, attached to struct or union type definition, specifies that each member (other than zero-width bitfields) of the structure or union is placed to minimize the memory required. When attached to an enum definition, it indicates that the smallest integral type should be used.
The attribute packed means that the compiler will not add padding between fields of the struct . Padding is usually used to make fields aligned to their natural size, because some architectures impose penalties for unaligned access or don't allow it at all.
When a structure is packed, these paddings are not inserted. The compiler has to generate more code (which runs slower) to extract the non-aligned data members, and also to write to them.
Yes, __attribute__((packed))
(no need for second set of underscores) is a correct way to implement binary (i.e. non-text) network protocols. There will be no gaps between the elements.
However you should understand that packed
not only packs the structure, but also:
However, the compiler will only deal with misalignment if you access the struct members directly. You should never make a pointer to a member of a packed struct (except when you know the member's required alignment is 1, like char or another packed struct). The following C code demonstrates the issue:
#include <stdio.h>
#include <inttypes.h>
#include <arpa/inet.h>
struct packet {
uint8_t x;
uint32_t y;
} __attribute__((packed));
int main ()
{
uint8_t bytes[5] = {1, 0, 0, 0, 2};
struct packet *p = (struct packet *)bytes;
// compiler handles misalignment because it knows that
// "struct packet" is packed
printf("y=%"PRIX32", ", ntohl(p->y));
// compiler does not handle misalignment - py does not inherit
// the packed attribute
uint32_t *py = &p->y;
printf("*py=%"PRIX32"\n", ntohl(*py));
return 0;
}
On an x86 system (which does not enforce memory access alignment), this will produce
y=2, *py=2
as expected. On the other hand on my ARM Linux board, for example, it produced the seemingly wrong result
y=2, *py=1
Assuming that you are asking whether the struct members will retain the order specified in their definition, the answer is yes. The Standard requires that successive members have increasing addresses:
Section §6.7.2.1p13:
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.
and the documentation for the packed attribute clearly states that only padding/alignment is affected:
The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable, and one bit for a field, unless you specify a larger value with the aligned attribute.
However, using __attribute__((__packed__))
is not a good way to do what you are doing.
Based on what you're trying to do, I'd highly encourage you to also used fixed-size data types (ie. uint32_t, int16_t, etc) that are found in stdint.h. Using fixed-size data types will prevent you from having to do things like the following:
struct name
{
short field : 8;
};
We use this technique frequently to convert messages between a byte array and a structure, and have never encountered problems with it. You may have to perform endianness conversion yourself, but field order isn't a problem. If you have any concerns about data type sizes, you can always specify field size like so:
struct foo
{
short someField : 16 __attribute__ ((packed));
};
This guarantees that someField will be stored as 16 bits and will not be rearranged or altered to fit byte boundaries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With