Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If I have three separate values that could all fit into 32 bits, does it make sense to use a uint to store them?

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?

like image 754
Dan Tao Avatar asked Aug 27 '10 19:08

Dan Tao


3 Answers

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.

like image 67
Dirk Vollmar Avatar answered Oct 13 '22 21:10

Dirk Vollmar


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.

like image 2
dthorpe Avatar answered Oct 13 '22 22:10

dthorpe


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

like image 1
Frank Avatar answered Oct 13 '22 21:10

Frank