london.pm Digest, Vol 11, Issue 22
David Brownlee
abs at absd.org
Thu Sep 14 01:07:24 BST 2006
On Wed, 13 Sep 2006, Dirk Koopman wrote:
> On Wed, 2006-09-13 at 17:26 +0100, David Cantrell wrote:
>
> > One of my own projects has been stalled for about a year because of
> > frustration that I need to feed a struct to a socket and read a struct
> > back. And that's just with one machine and one compiler. I *really*
> > don't want to hard-code whatever rules gcc uses for building x86 structs
> > into my module, because someone else might use Sun's compiler on Sparc,
> > or gcc on MIPS.
> >
> > Thou shalt abjure etc the vile heresy that all the world's a VAX^W
> > C program.
> >
>
> I do this sort of thing rather a lot. The exact solution depends on what
> sort of speed/portability/wrist-ache trade-off you want to make. But,
> even though gcc packed structure definitions seem to have settled down
> it still do it like this (ish E&OE)
>
> typedef struct {
> UC a SH, /* a short #define SH [2] */
> b LG, /* a long #define LG [4] */
> c FL, /* a float #define FL [4] */
> d DB, /* a double #define DB [8] */
> e [some define or other+1], /* string */
> f BY; /* a byte #define BY [1] */
> } foo_t;
>
> with a set of conversion routines
>
> US getsh(UC *)
> UL getlg(UC *)
> double getdb(UC *)
> etc
>
> void putsh(US, UC *)
> void putdb(double, UC *)
>
> etc
>
> The get and put routines standardise on which way around one stores the
> numbers in the arrays of bytes, I happen to use little endian, because
> that is what I deal with most. Obviously if you are not using IEEE
> floating point format then all bets are off.
>
> Bit tedious packing and unpacking arrays but I a have print/scanf
> equivalent which helps and it always just works...
I recently had need to do this for a C program and ended up
writing a small perl parser which would read a file containing
a list of structs such as:
typedef struct
{
uint32_t foo_version;
uint32_t random_token;
uint32_t ip_address;
uint16_t port;
uchar flags;
const char *name;
const char *arbitrary_url;
} msg_something_t;
Then for each struct generate C code from templates for
msg_something_extract() - populate struct from buffer
msg_something_alloc() - copy struct into buffer
msg_something_alloc_args() - as msg_X_alloc(), except given
list of args rather than struct
chars are sent as 16bit length followed by string.
It turns out to be relatively low overhead to serialise any arbitrary
struct, providing you are happy with a network neutral format for each
data type. Not handled nested structs or unions :)
In my case I have a short header that identifies the sender, recipient,
and struct type...
Amusingly enough I've done it twice, once for my own code and once
again for a closed source requirement at work...
More information about the london.pm
mailing list