C# 3-байтовые целые числа

Я работаю над проектом, в котором мне нужно иметь дело с целыми числами на уровне байтов. Поскольку экономия места является основным соображением, мне нужны только очень маленькие (целые числа переменной длины).

Есть ли способ превратить int «4096» в 3 байта? или «1053» в 2 байта?

Очевидно, я могу сделать это вручную = (byte[0] * 256) + (byte[1]), но мне было интересно, есть ли более простой вариант для преобразования int в x байтов и обратно?


person Ash    schedule 15.01.2009    source источник


Ответы (5)


Не могли бы вы? Конечно. Сэкономит ли это место? Может быть, в зависимости от того, сколько работы вы хотите сделать. Вы должны понимать, что процессор 32-битный, а это означает, что он имеет 4-байтовые регистры, так что именно так он захочет хранить и получать доступ к вещам. Чтобы принудительно использовать 3-байтовое «int», вам нужно сохранить его в массиве байтов и извлечь его из массива по выровненному адресу перед использованием. Это означает, что если вы сохраните его коротким, компилятор либо дополнит его (и вы потеряете всю эффективность, которую, по вашему мнению, создали), либо будет намного медленнее читать и писать.

Если это настольное приложение, то как именно экономия места является основным соображением, особенно когда речь идет о 1 байте на элемент? Штраф за доступ к элементу может изменить ваше мнение о том, насколько критичен этот байт.

Я бы сказал, что если этот 1 байт действительно важен, то, возможно, вы все равно используете неправильный язык. Количество байтов, которое вы бы сэкономили, если бы не устанавливали и не использовали CLR, в первую очередь составляет много этих байтов.

Боковое примечание: вы также сделаете сдвиг, а не умножение (хотя компилятор, скорее всего, сделает это за вас).

person ctacke    schedule 15.01.2009

Просто для пущего безумия давайте сделаем это на C#, используя старый трюк с объединением в стиле C:

[StructLayout(LayoutKind.Explicit)]
struct OddUnion
{
    /* The 32-bit integer value */
    [FieldOffset(0)]
    public int IntegerValue;

    /* The bytes that overlap with it */
    [FieldOffset(0)]
    public byte Byte1;
    [FieldOffset(1)]
    public byte Byte2;
    [FieldOffset(2)]
    public byte Byte3;
    [FieldOffset(3)]
    public byte Byte4;
 }

И затем, когда вы хотите «конвертировать», сделайте это:

OddUnion myOddUnion;
myOddUnion.IntegerValue = 4096;
Byte secondByte = myOddUnion.Byte1;

Но это действительно помогает только в том случае, если вы хотите «сэкономить» на стоимости битового сдвига одного байта из слова. Я не смотрел сгенерированный SMIL, поэтому не знаю, дешевле ли это по сравнению с любым другим решением.

person Shalom Craimer    schedule 15.01.2009
comment
Вместо этого я бы назвал это умным и сказал, что это кошмар обслуживания. - person ctacke; 29.01.2009
comment
@ctacke: ага! Совершенно не стоит, если только вы не делаете что-то с очень странным форматом бит/байт/слово. И даже тогда, все еще не рекомендуется. - person Shalom Craimer; 29.01.2009
comment
Если вы когда-нибудь запустите этот код на устройстве с обратным порядком байтов (маловероятно в случае C#, но не совсем невозможно), это, конечно, сломается. - person Tamas Czinege; 22.11.2009

Вы можете выполнить целочисленное кодирование переменной длины. Старый метод, применявшийся много лет назад, заключался в использовании старшего бита каждого байта для обозначения того, что целое число продолжается до другого байта. Таким образом, вы теряете один бит на байт, но получаете небольшие целые числа. Это в основном полезно в постоянном хранилище, где важен каждый последний байт.

Пример: предположим, что мы имеем дело с целыми числами без знака, у нас было бы

int  binary
0                       00000000
1                       00000001
...  
127                     01111111
128            00000001 10000000
129            00000001 10000001
...
255            00000001 11111111
256            00000010 10000000
...
16383          01111111 11111111
16384 00000001 10000000 10000000 

поэтому 0-127 занимает 1 байт, а 128-16383 занимает 2 байта и т. д.

Чтобы узнать о более сложных способах, посетите эту страницу.

person Amir    schedule 15.01.2009

BitConverter.GetBytes даст вам байты.

а также

BitConverter.ToInt32 даст вам 32-битное целое из байтов.

person Allain Lalonde    schedule 15.01.2009

Вы должны сделать некоторые сдвиги бит. Это намного проще, если вы работаете с HEX, поскольку каждое число (я имею в виду каждую цифру, но цифра для базы 10, hexgit) представляет четыре бита.

person Igor Zelaya    schedule 15.01.2009