Binary Serialization

Adam D. Ruppe destructionator at gmail.com
Sun Jul 14 00:18:02 UTC 2019


On Saturday, 13 July 2019 at 23:52:38 UTC, harakim wrote:
> class MoveCommand
> {
> 	byte serialNumber;
> 	int x;
> 	int y;
> }
> When I do MoveCommand.sizeof, it returns 4.


It is important to understand a class in D is a reference type, 
so `MoveCommand` here is actually a pointer internally, meaning 
that 4 is the size of a pointer. Trying to directly read or write 
that to a socket is a mistake.

With struct though, there's potential. The reason you get 12 
there though is that the byte is padded. The struct looks like

0: serialNumber
1: padding
2: padding
3: padding
4: x
5: x
6: x
7: x
8: y
9: y
10: y
11: y


To get move the padding to the end, you can add `align(1):` 
inside, so given:

struct MoveCommand
{
   align(1):
  	byte serialNumber;
	int x;
	int y;
}

The layout will look like this:

0: serialNumber
1: x
2: x
3: x
4: x
5: y
6: y
7: y
8: y
9: padding
10: padding
11: padding


The align(1) is kinda like the __packed__ thing in C compilers. 
The size of will still read 12 there, but you can read and write 
an individual item direct off a binary thing reliably. But an 
array of them will have that padding still. To get rid of that, 
you put an align(1) on the *outside* of the struct:

align(1) // this one added
struct MoveCommand
{
   align(1): // in ADDITION to this one
  	byte serialNumber;
	int x;
	int y;
}


And now the sizeof will read 9, with the padding cut off fromt 
the end too. You can do an array of these now totally packed.


This behavior is consistent across D compilers; it is defined by 
the spec.

Just remember types like `string` have a pointer embedded and 
probably shouldn't be memcpyed!


More information about the Digitalmars-d-learn mailing list