Если у меня есть три отдельных значения, которые могут вписаться в 32 бита, имеет ли смысл использовать uint для их хранения? - PullRequest
5 голосов
/ 27 августа 2010

Я имею в виду, скажем, у меня есть struct для представления некоторых данных, и это выглядит так:

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 и два значения byte могут уместиться в 32 бита. Что мне интересно, так это (для целей выравнивания, производительности, чего угодно), если бы на самом деле имело смысл хранить эти данные в следующем формате:

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); }
    }
}

Это бессмысленно? Каковы будут преимущества / недостатки?

Ответы [ 5 ]

3 голосов
/ 27 августа 2010

В .NET, если вы все равно собираетесь использовать struct, вы также можете украсить структуру с помощью StructLayoutAttribute следующим образом:

[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;
    }
}

Это приведет к тому, что поля будут расположены последовательно, например, поле B начнется со смещения 16.

Значение 1 для Pack означает, что поля выровнены по границам byte.

2 голосов
/ 27 августа 2010

Вам следует рассмотреть возможность объединения нескольких значений в uint, если значения тесно связаны друг с другом, обычно передаются вместе и никогда или очень редко изменяются независимо друг от друга. Стоимость распаковки и повторной упаковки uint с целью изменения его значения делает это очень дорогим (по размеру кода и времени выполнения) по сравнению с простым хранением трех байтов отдельно.

При выполнении на микроустройстве с общим объемом оперативной памяти 10 Кбайт такая упаковка может стоить того, потому что память важнее скорости выполнения. На обычном настольном ПК или даже мобильном устройстве эта упаковка, вероятно, не стоит усилий.

1 голос
/ 27 августа 2010

Вы можете остаться со своим определением структуры и применить атрибут StructLayout со значением StructLayoutAttribute.Pack , равным 1. Но на самом деле вы, вероятно, сэкономите немного памятиза счет скорости доступа, так как таким образом данные не будут размещаться в памяти наиболее эффективным способом доступа.Обычно компилятор размещает память таким образом, чтобы к ней был эффективный доступ, и он не испортил бы слишком много памяти автоматически.

Этот подход, по крайней мере, сделает ваш код более понятным, чем предложенный вами метод сдвига битов (которыйна самом деле может быть или не быть похожим на то, что компилятор машинного кода будет генерировать из байтового кода).

0 голосов
/ 28 августа 2010

Есть несколько случаев, когда стоит втиснуть материал в целое число.Пространство памяти обычно не является хорошей причиной, но если значения будут использоваться вместе, например, как ключ для словаря, словарь (целочисленный, безотносительно) будет намного быстрее, чем словарь (некоей структуры, безотносительно).

0 голосов
/ 27 августа 2010

То, с чем вы столкнетесь, - это простой компромисс между размером ваших данных в памяти и стоимостью обработки.Если память представляет собой реальную проблему, может быть просто дешевле использовать больше памяти на вашем компьютере.

...