On Mon, Jun 30, 2014 at 08:54:52PM +0200, Markus Teich wrote:
> Heyho,
> 
> since I did not find any suckless project regarding this issue, I would like 
> to
> ask you guys for some feedback:
> 
> 
> unsigned char *msg;
> size_t msg_size;
> struct foo *msg_data;
> struct bar *msg_signature;
> 
> msg_size = sizeof(unsigned char)        // op
>       + sizeof(struct foo)    // data
>       + sizeof(struct bar)    // signature
> msg = malloc(msg_size);
> 
> *msg = MSG_OP_SIGNED_DATA;
> 
> msg_data = (struct foo *)(msg + 1);
> msg_data->field0 = bla;
> msg_data->field1 = blub;
> 
> msg_signature = (struct bar *)(msg_data + 1);
> create_signature(msg, msg_signature);
> 
> sendmsg(msg);
> 
> free(msg);
> 
> 
> I feel it is pretty good already compared to other message packing I've seen,
> but do you know a way to make it suck even less?
> 
> --Markus
> 

The alignment issue was already mentioned (there's nothing like your
program working at home and then suddenly dying of SIGBUS in the field
to hammer that point home), but unless all your data is single bytes,
you also have byte order problems. Solving these requires some suck.

There are basically only two ways to resolve these problems: Either copy
the data into the buffer and flip it later, or flip it on the way. I'd
personally go with flipping on the way:

unsigned char *p = msg;
*p++ = MSG_OP_SIGNED_DATA;
align32(&p, msg);
write_be32(&p, bla);
write_be16(&p, blub);
/* and so on */

Then implement them like:

void write_be32(unsigned char **p, uint32_t i)
{
    *(*p)++ = i >> 24;
    *(*p)++ = i >> 16;
    *(*p)++ = i >>  8;
    *(*p)++ = i;
}

Then you are even independent of the host processor's byte order.

HTH,
Markus

Reply via email to