There are a few ways to do this:
// packet.h
////////////////
struct Packet {
unsigned char a;
unsigned char b;
unsigned int c;
};
If you compile and dump the structs with pahole
you will see the paddings
$ pahole -dr --structs main.o
struct Packet {
unsigned char a; /* 0 1 */
unsigned char b; /* 1 1 */
/* XXX 2 bytes hole, try to pack */
unsigned int c; /* 4 4 */
/* size: 8, cachelines: 1, members: 3 */
/* sum members: 6, holes: 1, sum holes: 2 */
/* last cacheline: 8 bytes */
};
So it's basically the 2 chars, 2 padding bytes and 4 bytes of an int for a total of 8 bytes.
Because Intel is a little endian platform, the least significant byte comes first as in
void print_packet( Packet* pkt ) {
printf( "a:%d b:%d c:%d\n", int(a), int(b), c );
}
int main() {
unsigned char buffer[] = {1, 1, 0, 0, 1, 0, 0, 0};
print_packet( (Packet*) buffer );
print_packet( reinterpret_cast<Packet*>(buffer));
}
Produces:
$ g++ main.cpp -o main
$ ./main
a:1 b:1 c:1
a:1 b:1 c:1
However one can change the packing from the command line as below where we set the alignment to 2 bytes.
$ g++ -ggdb main.cpp -o main -fpack-struct=2
$ pahole -dr --structs main
struct Packet {
unsigned char a; /* 0 1 */
unsigned char b; /* 1 1 */
unsigned int c; /* 2 4 */
/* size: 6, cachelines: 1, members: 3 */
/* last cacheline: 6 bytes */
} __attribute__((__packed__));
Then you can see that the Packet struct is only 6 bytes and the result of running main is completely different
$ ./main
a:1 b:1 c:65536
a:1 b:1 c:65536
This is because the value of c
is now 0x00000100
or 65536
So not to be at mercy of these compiler shenanigans, it is better to define your packet in code with the right packing as
// packet.h
////////////////
struct [[gnu::packed]] Packet {
unsigned char a;
unsigned char b;
unsigned char reserved[2];
unsigned int c;
};
Then execution becomes
$ g++ -ggdb main.cpp x.cpp -o main -fpack-struct=2
$ ./main
a:1 b:1 c:1
a:1 b:1 c:1
$ g++ -ggdb main.cpp x.cpp -o main -fpack-struct=4
$ ./main
a:1 b:1 c:1
a:1 b:1 c:1
$ g++ -ggdb main.cpp x.cpp -o main -fpack-struct=8
$ ./main
a:1 b:1 c:1
a:1 b:1 c:1
$ g++ -ggdb main.cpp x.cpp -o main -fpack-struct=16
$ ./main
a:1 b:1 c:1
a:1 b:1 c:1