views:

67

answers:

5

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?

+3  A: 

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.

0xA3
Ah! Very useful to know!
Dan Tao
A: 

What you will encounter is a simple trade-off between the size of your in-memory data objects and the cost of processing. If memory is a real concern, it may simply be cheaper to throw more RAM at your machine.

kbrimington
+2  A: 

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.

dthorpe
+1  A: 

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).

Frank
A: 

There are a few cases when it's worthwhile to cram stuff into an integer. Storage space alone is usually not a good reason, but if the values are going to be used together as e.g. a key for a Dictionary, a Dictionary(Of Integer, Whatever) will be much faster than a Dictionary(Of SomeStructure, Whatever).

supercat