Что такое идиоматический c # для распаковки целого числа из байтового массива? - PullRequest
1 голос
/ 19 мая 2009

Я анализирую двоичный формат файла. Он кодирует целое число, используя четыре байта, таким образом, что он естественно помещается в тип uint в c #.

Какой самый C # / идиоматический способ реализации этой функции:

uint ReadUint(byte[] buffer);

Предположим, что буфер содержит 4 элемента. В полном ответе могут быть рассмотрены некоторые из общих порядков байтов, вызванных небольшими / большими порядковыми номерами в файле, и задокументированы те, которые он выбрал для анализа.

Ответы [ 7 ]

5 голосов
/ 19 мая 2009

Самое основное (но немного опасное повторение):

return BitConverter.ToUInt32(buffer, 0);

Помимо, смещение бит хорошо (согласно вашему собственному ответу) - или вы можете использовать Jian's EndianBitConverter в MiscUtil , который обрабатывает переводы.

(редактировать)

Версия с прямым порядком байтов, которую я использую в protobuf-net, почти идентична вашей версии - я просто читаю их в порядке возрастания и использую побитовое (не числовое) дополнение:

return ((uint)buffer[0])
        | (((uint)buffer[1]) << 8)
        | (((uint)buffer[2]) << 16)
        | (((uint)buffer[3]) << 24);
2 голосов
/ 19 мая 2009

Этот ответ на самом деле является расширенным комментарием (следовательно, вики), сравнивающим производительность BitConverter и сдвига битов с помощью + vs | применяется только при микрооптимизации !!

Результаты сначала:

BitConverter: 972ms, chk=1855032704
Bitwise: 740ms, chk=1855032704
ReadLength: 1316ms, chk=1855032704

Или результаты, если настроены на ненулевые базовые смещения:

BitConverter: 905ms, chk=1855032704
Bitwise: 1058ms, chk=1855032704
ReadLength: 1244ms, chk=1855032704

И код:

using System;
using System.Diagnostics;
static class Program
{
    static void Main()
    {
        byte[] buffer = BitConverter.GetBytes((uint)123);
        const int LOOP = 50000000;
        uint chk = 0;
        var watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += BitConverter.ToUInt32(buffer, 0);
        }
        watch.Stop();
        Console.WriteLine("BitConverter: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += Bitwise(buffer);
        }
        watch.Stop();
        Console.WriteLine("Bitwise: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += ReadLength(buffer);
        }
        watch.Stop();
        Console.WriteLine("ReadLength: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        Console.ReadKey();
    }
    static uint Bitwise(byte[] buffer)
    {
        return ((uint)buffer[0])
            | (((uint)buffer[1]) << 8)
            | (((uint)buffer[2]) << 16)
            | (((uint)buffer[3]) << 24);
    }
    static uint ReadLength(byte[] buffer)
    {
        uint result = ((uint)buffer[3]) << 24;
        result += ((uint)buffer[2]) << 16;
        result += ((uint)buffer[1]) << 8;
        result += buffer[0];
        return result;
    }
}
2 голосов
/ 19 мая 2009

Я бы обычно использовал для этого класс BitConverter. В вашем случае метод BitConverter.ToUInt32 () .

1 голос
/ 19 мая 2009

Как кто-то из C, вот как я сейчас реализую эту функцию:

static uint ReadLength(byte[] buffer)
{
    uint result = ((uint) buffer[3]) << 24;
    result |= ((uint) buffer[2]) << 16;
    result |= ((uint) buffer[1]) << 8;
    result |= buffer[offset];
    return result;
}

Этот синтаксический анализ формата, который, как утверждает Википедия, выложен в порядке байтов для реализации .net, работающей на i386 / Vista

0 голосов
/ 19 мая 2009

Самый простой способ это просто

int val  = System.BitConverter.ToInt32(buffer, 0);

Используется текущий порядковый номер системы, который может быть, а может и не быть тем, что вы хотите.

0 голосов
/ 19 мая 2009
byte[] ba = new byte[]{ 0x10, 0xFF, 0x11, 0x01 } ;
var ui = BitConverter.ToUInt32(ba, 0);

Используйте Класс BitConverter .

0 голосов
/ 19 мая 2009

Предполагая, что вы хотите прочитать их поток (как подсказывает ваш код) Я бы сказал, что это довольно близко к стандартному стандарту де-факто:

MemoryStream ms = new MemoryStream(new byte[100]);
BinaryReader br = new BinaryReader(ms);
uint q = br.ReadUInt32();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...