#include <iostream>
#include <iomanip>
using namespace std;
// The holes between members of the structure
// are implementation specific, as are the
// contents of those holes when you fill in
// a struct.
struct foo {
char a;
int b;
};
// You can try and squeeze out the holes, but
// how you ask the compiler to do this is
// compiler specific
#pragma pack(1)
struct bar {
char a;
int b;
};
// A little something to show all the bytes
void dumpHex ( void *p, size_t size ) {
unsigned char *bytes = (unsigned char *)p;
for ( size_t i = 0 ; i < size ; i++ ) {
unsigned int b = bytes[i];
cout << setw(2) << setbase(16) << b << " ";
}
cout << endl;
}
// Just one way of packing a struct
size_t packFoo ( foo v1, unsigned char *ba ) {
size_t used = 0;
memmove ( &ba[used], &v1.a, sizeof v1.a );
used += sizeof v1.a;
memmove ( &ba[used], &v1.b, sizeof v1.b );
used += sizeof v1.b;
return used;
}
size_t packBar ( bar v1, unsigned char *ba ) {
size_t used = 0;
memmove ( &ba[used], &v1.a, sizeof v1.a );
used += sizeof v1.a;
memmove ( &ba[used], &v1.b, sizeof v1.b );
used += sizeof v1.b;
return used;
}
void packdemo ( foo &v1, bar &v2 ) {
unsigned char b1[sizeof(foo)]; // worst-case, it packs into its
unsigned char b2[sizeof(bar)]; // own size.
size_t s1 = packFoo( v1, b1 );
size_t s2 = packBar( v2, b2 );
cout << "Packed size of foo is " << s1 << endl;
dumpHex ( b1, s1 );
// expect nothing here, the #pragma pack(1) had done
// all the work
cout << "Packed size of bar is " << s2 << endl;
dumpHex ( b2, s2 );
}
int main ( ) {
foo v1 = { 'a', 0x1234 };
bar v2 = { 'a', 0x1234 };
cout << "size of foo " << sizeof(foo) << endl;
dumpHex ( &v1, sizeof v1 );
cout << "size of bar " << sizeof(bar) << endl;
dumpHex ( &v2, sizeof v2 );
packdemo(v1,v2);
return 0;
}
My output
$ ./a.out
size of foo 8
61 9c 54 0 34 12 0 0
size of bar 5
61 34 12 0 0
Packed size of foo is 5
61 34 12 0 0
Packed size of bar is 5
61 34 12 0 0