It's missing floating points, so you'd have to figure that out for your particular machine.. But I've used the following.
/*Just for "consistency" */
#define UNPACK8(p) ((p)[0])
#define PACK8(p,v) (p)[0]=(v)
#define UNPACK16LE(p) ((p)[0]|((p)[1]<<8))
#define UNPACK32LE(p) ((p)[0]|((p)[1]<<8UL)|((p)[2]<<16UL)|((p)[3]<<24UL))
#define UNPACK64LE(p) (((p)[0]|((p)[1]<<8ULL)|((p)[2]<<16ULL)|((p)[3]<<24ULL)) |\
(((p)[4]|((p)[5]<<8ULL)|((p)[6]<<16)|((p)[7]<<24ULL)) << 32ULL))
#define PACK16LE(p,v) (p)[0]=(v);(p)[1]=(v)>>8
#define PACK32LE(p,v) (p)[0]=(v);(p)[1]=(v)>>8UL;(p)[2]=(v)>>16UL;(p)[3]=(v)>>24UL
#define PACK64LE(p,v) (p)[0]=(v);(p)[1]=(v)>>8ULL;(p)[2]=(v)>>16ULL;(p)[3]=(v)>>24ULL;\
(p)[4]=(v)>>32ULL;(p)[5]=(v)>>40ULL;(p)[6]=(v)>>48ULL;(p)[7]=(v)>>56ULL
#define UNPACK16BE(p) ((p)[1]|((p)[0]<<8))
#define UNPACK32BE(p) ((p)[3]|((p)[2]<<8UL)|((p)[1]<<16UL)|((p)[0]<<24UL))
#define UNPACK64BE(p) (((p)[7]|((p)[6]<<8ULL)|((p)[5]<<16ULL)|((p)[4]<<24ULL)) |\
(((p)[3]|((p)[2]<<8ULL)|((p)[1]<<16)|((p)[0]<<24ULL)) << 32ULL))
#define PACK16BE(p,v) (p)[1]=(v);(p)[0]=(v)>>8
#define PACK32BE(p,v) (p)[3]=(v);(p)[2]=(v)>>8UL;(p)[1]=(v)>>16UL;(p)[0]=(v)>>24UL
#define PACK64BE(p,v) (p)[7]=(v);(p)[6]=(v)>>8ULL;(p)[5]=(v)>>16ULL;(p)[4]=(v)>>24ULL;\
(p)[3]=(v)>>32ULL;(p)[2]=(v)>>40ULL;(p)[1]=(v)>>48ULL;(p)[0]=(v)>>56ULL
void
vapickle(uint8_t * buf, const char *fmt, va_list args)
{
const char *fp;
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
for (fp = fmt; *fp; fp++) {
switch (*fp) {
case 'b':
u8 = va_arg(args, unsigned int);
PACK8(buf,u8);
++buf;
break;
case 'S':
u16= va_arg(args,unsigned int);
PACK16BE(buf,u16);
buf+=2;
break;
case 'I':
u32 = va_arg(args, unsigned int);
PACK32BE(buf,u32);
buf+=4;
break;
case 'L':
u64 = va_arg(args, unsigned long long);
PACK32BE(buf,u32);
buf+=8;
break;
case 's':
u16= va_arg(args,unsigned int);
PACK16LE(buf,u16);
buf+=2;
break;
case 'i':
u32 = va_arg(args, unsigned int);
PACK32LE(buf,u32);
buf+=4;
break;
case 'l':
u64 = va_arg(args, uint64_t);
PACK32LE(buf,u64);
buf+=8;
break;
case ' ':
++buf;
break;
}
}
}
void
pickle(uint8_t *buf, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vapickle(buf, fmt, args);
va_end(args);
}
void
vadepickle(const uint8_t*buf, const char *fmt, va_list args)
{
const char *fp;
uint8_t *u8;
uint16_t *u16;
uint32_t *u32;
uint64_t *u64;
for (fp = fmt; *fp; fp++) {
switch (*fp) {
case 'b':
u8 = va_arg(args, uint8_t*);
*u8 = UNPACK8(buf);
++buf;
break;
case 'S':
u16= va_arg(args, uint16_t*);
*u16 = UNPACK16BE(buf);
buf+=2;
break;
case 'I':
u32 = va_arg(args, uint32_t*);
*u32 = UNPACK32BE(buf);
buf+=4;
break;
case 'L':
u64 = va_arg(args, uint64_t*);
*u64 = UNPACK32BE(buf);
buf+=8;
break;
case 's':
u16 = va_arg(args,uint16_t*);
*u16 = UNPACK16LE(buf);
buf+=2;
break;
case 'i':
u32 = va_arg(args, uint32_t*);
*u32 = UNPACK32LE(buf);
buf+=4;
break;
case 'l':
u64 = va_arg(args, uint64_t*);
*u64 = UNPACK32LE(buf);
buf+=8;
break;
case ' ':
++buf;
break;
}
}
}
void
depickle(const uint8_t *buf, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vadepickle(buf, fmt, args);
va_end(args);
}
int main(void)
{
uint32_t i = 0x123456;
uint16_t j = 0xabab;
uint16_t k = 0xbbab;
uint8_t buf[8]; /* keep this big enough according to the format string */
pickle(buf,"sis",j,i,k); /*s=uint16, little endian. i = uint32, litte endian, S = uint16 big endian etc.*/
write(1,buf,sizeof buf);
read(0,buf,sizeof buf);
depickle(buf,"SiS",&j,&i,&k);
return 1;
}