Tor said:
I had a buffer in mind, which is the typical case when a network packet
arrives or you read some data from disk.
Put another way, if you have a buffer
char buf[1024];
which has some received network packet in it, you can't do
struct packet_header *header=(struct packet_header *)buf;
and start reading the members of header and expect everything to be
fine. The packet has all members aligned according to the network
protocol, probably with very little padding, and the compiler probably
aligns for instance ints and chars differently, inserting padding in
between them or even reordering them inside the struct. There are no
guarantees (well almost no guarantees, go read the standard).
So, as an example, say you have a network protocol with a header that
contains an 8 bit packet type and a 16 bit payload length. It probably
looks like this:
offset 0: type [byte]
offset 1: length [high byte] [low byte]
Now if you declare a struct for that as
struct header{
char type;
short length;
};
on a little-endian 32 bit computer with no native 16 bit data type and a
32 bit alignment restriction, you'll probably get a struct that looks
like this in memory:
offset 0: type [byte]
offset 1: [padding] [padding] [padding]
offset 4: length [low byte] [2:nd byte]
[3:rd byte] [high byte]
If you set a pointer like that to the beginning of the buffer and try to
read the members, you'll get the right packet type, but the length will
be outside of the header data and might segfault your program, or it
might point to the second byte of the payload, or it might point to
something else entirely.
Without the padding, the length member of the struct would start at the
right place but would still read four bytes instead if the two defined
in the protocol and present in the buffer, and on top of that they would
be in the wrong order.
So that was a quick lesson in padding and network byte order.
Bjarni