What I mean is, say I have a struct
to represent some data and it looks like this:
struct LilStruct
{
public readonly short A;
public readonly byte B;
public readonly byte C;
public LilStruct(short a, byte b, byte c)
{
A = a;
B = b;
C = c;
}
}
A short
and two byte
values could all fit into 32 bits. What I'm wondering is (for alignment purposes, performance, whatever) if it would actually make sense to store this data in the following format instead:
struct LilStruct
{
private readonly uint _value;
public LilStruct(short a, byte b, byte c)
{
_value = ((uint)a << 16) | ((uint)b << 8) | (uint)c;
}
public int A
{
get { return (int)(_value >> 16); }
}
public int B
{
get { return (int)(_value >> 8) & 0x000000FF; }
}
public int C
{
get { return (int)(_value & 0x000000FF); }
}
}
Is this pointless? What would be the benefits/drawbacks?
In .NET, when you are going to use a struct
anyway, you can as well decorate the struct with StructLayoutAttribute
like this:
[StructLayout(LayoutKind.Sequential, Pack=1)]
struct LilStruct
{
public readonly short A;
public readonly byte B;
public readonly byte C;
public LilStruct(short a, byte b, byte c)
{
A = a;
B = b;
C = c;
}
}
This will have the effect that the fields are laid out sequentially, e.g. field B
will start at offset 16.
A value of 1 for Pack
means that the fields are aligned at the byte
boundaries.
You should only consider cramming multiple values into a uint if the values are closely tied to each other, usually passed around together, and are never or very rarely modified independently of each other. The cost of unpacking and repacking the uint in order to modify its value makes this very expensive (in code size and execution time) compared to just storing three bytes separately.
When executing on a microdevice with a total of 10k bytes of RAM, packing like this might be worth it because memory is more precious than execution speed. On a normal desktop PC or even mobile phone device, this packing is probably not worth the effort.
You could stay with your struct definition, and apply the StructLayout attribute with an StructLayoutAttribute.Pack value of 1. But in fact, you will probably save a little bit of memory at the expense of access speed, as this way the data would not be laid out in memory in a way that is most efficient to access. The compiler normally would lay out the memory in a way that is efficient to access and would not spoil too much memory automatically.
This approach would at least keep your code more understandable than the bit shifting approach you proposed (which might or might not in fact still be similar to what the machine code compiler would generate from the byte code).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With