What you want would need your version
and length
to have the same length as 2 elements of your buf
array; that is you'd need to use the type uint16_t
, defined in <cstdint>
, rather than int
which is likely longer. And also you'd need to make buf
an array of uint8_t
, as char is allowed to take more than 1 byte!
You probably also need to move type
to the end; as otherwise the compiler will almost certainly insert a padding byte after it to be able to align version
to a 2-byte boundary (once you have made it uint16_t
and thus 2 bytes); and then your buf[1]
would end up there rather than were you want it.
This is probably what you observe right now, by the way: by having a char
followed by an int
, which is probably 4
bytes, you have 3
bytes of padding, and the elements 1
to 3
of your array are being inserted there (=lost forever).
Another solution would be to modify your buf
array to be longer and have empty padding bytes as well, so that the data will be actually aligned with the struct fields.
Worth mentioning again is that, as pointed out in the comments, sizeof(head)
returns the size of pointers on your system, not of the Header
structure. You can directly write sizeof(Header)
; but at this level of micromanagement, you wont be losing any more flexibility if you just write "5
", really.
Also, endianness can screw with you. Processors have no obbligation to store the bytes of a number in the order you expect rather than the opposite one; both make internal sense after all. This means that blindly copying bytes buf[0], buf[1]
into a number can result in (buf[0]<<8)+buf[1]
, but also in (buf[1]<<8)+buf[0]
, or even in (buf[1]<<24)+(buf[0]<<16)
if the data type is 4
bytes (as int
usually is). And even if it works on your computer now, there is at least one out there where the same code will result in garbage. Unless, that is, those bytes actually come from reinterpreting a number in the first place. In which case the code is wrong (not portable) now, however.
...is it worth it?
All things considered, my advice is strongly to keep the way you handle them now. Maybe simplify it.
It really makes no sense to convert a byte to an int then to byte again, or to take the address of a byte to dereference it again, nor there is need of helper variables with no descriptive name and no purpose other than being returned, or of a variable whose value you know in advance at all time.
Just do
int getTwoBytes(unsigned char* buf)
{
return (buf[0]<<8)+buf[1];
}
main()
{
Header *head = new Header;
head->type = buf[0];
head->version = getTwoBytes(buf + 1);
head->length = getTwoBytes(buf + 3);
}