簡體   English   中英

從字節數組解包整數的慣用c#是什么?

[英]What is the idiomatic c# for unpacking an integer from a byte array?

我正在解析二進制文件格式。 它使用四個字節對整數進行編碼,這自然會適合c#的uint類型。

實現此功能的最C#/慣用方式是什么:

uint ReadUint(byte[] buffer);

假設緩沖區包含4個元素。 一個完整的答案可能會考慮文件中字節序大/小假設引起的一些常見字節順序,並記錄它選擇解析的字節序。

最基本的(但有點危險的字節序)是:

return BitConverter.ToUInt32(buffer, 0);

除此之外,可以使用位移(根據您自己的答復)-或者您可以在MiscUtil中使用Jon的EndianBitConverter來處理翻譯。

(編輯)

我在protobuf-net中使用的Little-endian移位版本與您的版本幾乎完全相同-我只是按升序閱讀並使用按位(非數字)加法:

return ((uint)buffer[0])
        | (((uint)buffer[1]) << 8)
        | (((uint)buffer[2]) << 16)
        | (((uint)buffer[3]) << 24);

我通常會為此使用BitConverter類。 在您的情況下, BitConverter.ToUInt32()方法。

該回復實際上是一個擴展注釋(因此,Wiki),使用+ vs |比較BitConverter和移位的性能。 僅在微優化時適用!!

結果優先:

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

作為來自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;
}

這將解析Wikipedia聲稱的格式,該格式是在i386 / Vista上運行的.net實現上以低位字節序排列的。

假設您想讀取它們的流(如您的代碼所建議的那樣),我會說這與事實上的標准方法非常接近:

MemoryStream ms = new MemoryStream(new byte[100]);
BinaryReader br = new BinaryReader(ms);
uint q = br.ReadUInt32();
byte[] ba = new byte[]{ 0x10, 0xFF, 0x11, 0x01 } ;
var ui = BitConverter.ToUInt32(ba, 0);

使用BitConverter類

最簡單的方法就是

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

這將使用當前的系統字節序,它可能是您想要的,也可能不是。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM