簡體   English   中英

如何從 C# 中具有偏移量和位大小的 byte[] 讀取 int

[英]How to read an int from a byte[] with an offset and a size of bits in C#

我需要一個將偏移量和位大小作為參數的函數,以從字節數組中讀取 int 值。

int GetInt(byte[] data, int bitOffset, int bitSize)

例如,我有以下字節數組:

66 DC 00 00 6A DC 00 00
66 DC 00 00 58 DC 00 00
54 DC 00 00 50 DC 00 00
4C DC 00 00 00 00 00 00
00 00 00 00 00 00 00 08
F0 FF FF 9F F4 7F 20 9A
91 EB 85 88 3F 6E 00 80
3D 6E 00 80 3B 6E 00 00

位相同:

01100110  00111011  00000000  00000000  01010110  00111011  00000000  00000000
01100110  00111011  00000000  00000000  00011010  00111011  00000000  00000000
00101010  00111011  00000000  00000000  00001010  00111011  00000000  00000000
00110010  00111011  00000000  00000000  00000000  00000000  00000000  00000000
00000000  00000000  00000000  00000000  00000000  00000000  00000000  00010000
00001111  11111111  11111111  11111001  00101111  11111110  00000100  01011001
10001001  11010111  10100001  00010001  11111100  01110110  00000000  00000001
10111100  01110110  00000000  00000001  11011100  01110110  00000000  00000000

如何最有效地確保以下函數具有這些返回值?:

var a = GetInt(data, 0, 32); // a = 56422
var b = GetInt(data, 313, 11); // b = 4

在此處輸入圖像描述

編輯:這里的字節作為 C# 數組:

new byte[] { 0x66, 0xDC, 0x00, 0x00, 0x6A, 0xDC, 0x00, 0x00, 0x66, 0xDC, 0x00, 0x00, 0x58, 0xDC, 0x00, 0x00, 0x54, 0xDC, 0x00, 0x00, 0x50, 0xDC, 0x00, 0x00, 0x4C, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xF0, 0xFF, 0xFF, 0x9F, 0xF4, 0x7F, 0x20, 0x9A, 0x91, 0xEB, 0x85, 0x88, 0x3F, 0x6E, 0x00, 0x80, 0x3D, 0x6E, 0x00, 0x80, 0x3B, 0x6E, 0x00, 0x00 }

編輯 2:我也已經實現了自己的解決方案,我可以在這里獲取這篇文章的所有值。 我對我的解決方案非常不滿意,因為我不想每次都將數組傳遞給 BitArray。 要讀取一個文件,這個函數會被調用幾十萬次。

public static int GetdInt(this byte[] data, int bitOffset, int bitSize)
{
    var bits = new BitArray(data);

    var output = 0;

    for(var bitIndex = 0; bitIndex < bitSize; bitIndex++)
    {
        var bit = bits.Get(bitOffset + bitIndex) ? 1 : 0;
        output |= bit << bitIndex;
    }

    return output;
}

C# 90 字節

    int GetInt(byte[] d,int o,int b)=>Enumerable.Range(o,b).Sum(i=>(d[i/8]>>i%8)%2>0?1<<i-o:0);

我用代碼打高爾夫球的形式寫了這個來取笑你的問題讀起來像打高爾夫球,而且你沒有表現出你自己的任何嘗試;)

這是任何未來回答者的單元測試。 (OP,這也可能對您有所幫助):

[TestMethod]
public void Test()
{
    var bytes = new byte[]
    {
        0x66, 0xDC, 0x00, 0x00, 0x6A, 0xDC, 0x00, 0x00,
        0x66, 0xDC, 0x00, 0x00, 0x58, 0xDC, 0x00, 0x00,
        0x54, 0xDC, 0x00, 0x00, 0x50, 0xDC, 0x00, 0x00,
        0x4C, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
        0xF0, 0xFF, 0xFF, 0x9F, 0xF4, 0x7F, 0x20, 0x9A,
        0x91, 0xEB, 0x85, 0x88, 0x3F, 0x6E, 0x00, 0x80,
        0x3D, 0x6E, 0x00, 0x80, 0x3B, 0x6E, 0x00, 0x00
    };
    RunTest(0, 32, 56422);
    RunTest(313, 11, 4);

    void RunTest(int offset, int bitSize, int expected)
    {
        var actual = GetInt(bytes, offset, bitSize);
        Assert.AreEqual(actual, expected);
    }
}

編輯:由於您在這里展示了自己的嘗試,因此這是一個非代碼高爾夫球的答案:

//first write a function that gets a bit value from the byte[]
bool GetBitFromByteArray(byte[] data, int bitNumber)
{
    //8 bits per byte.
    const int sizeOfByte = 8;
    
    var byteNumber = bitNumber / sizeOfByte;//index within the byte array. Integer division always rounds down
    var bitNumberWithinTheByte = bitNumber % sizeOfByte;//bit index within that byte

    //now write a function that gets a bit value from a byte
    return GetBitFromByte(data[byteNumber], bitNumberWithinTheByte);
}

bool GetBitFromByte(byte byteValue, int bitNumber)
{
    //bit shift so that the bit in question is in the least significant place
    var shifted = byteValue >> bitNumber;

    //mod 2 checks if the least significant bit is 0 or 1
    return shifted % 2 > 0;
}

int GetInt(byte[] data, int offset, int bitCount)
{
    //get bit values in order
    var bitValues = new List<bool>(bitCount);
    for (int i = 0; i < bitCount; i++)
    {
        bitValues.Add(GetBitFromByteArray(data, i + offset));
    }

    //sum up the bit values as powers of 2
    var intValue = 0;
    for (int i = 0; i < bitCount; i++)
    {
        var bitValue = bitValues[i];
        if (bitValue) intValue += 1 << i;//1<<i is equivalent to 2^i
    }

    return intValue;
}

如果您擔心性能和數組分配,那么代碼打高爾夫球的答案實際上會更好。

使用BitArrayBitConverter的解決方案

int GetInt(byte[] data, int bitOffset, int bitSize)
{
    var bits = new BitArray(data).RightShift(bitOffset);
    bits.Length = bitSize;
    var bytes = new byte[4];
    bits.CopyTo(bytes, 0);
    return BitConverter.ToInt32(bytes);
}

這是一種可能的策略,一個接一個地讀取字節,直到讀取了足夠的位,然后丟棄任何多余的位。 通過了兩個測試用例,但這還不夠測試 IMO,多做一些。

static int GetInt(byte[] data, int bitOffset, int bitSize)
{
    // first chunk is special, lower bits are discarded immediately
    // to prevent trying to put more than 32 bits in `result`
    // when `bitSize == 32` and `bitOffset != 0`
    int byteOffset = bitOffset >> 3;
    int result = data[byteOffset] >> (bitOffset & 7);
    int resultOffset = 8 - (bitOffset & 7);
    // the "rest", whole bytes are read from data and put into their place in the result
    while (resultOffset < bitSize)
    {
        byteOffset++;
        result |= data[byteOffset] << resultOffset;
        resultOffset += 8;
    }
    // in general too many bits have been read at this point, discard excess
    return result & (int)(uint.MaxValue >> -bitSize);
}

還有其他可能的策略。 例如,使用BitConverter類(或其他技巧)讀取整個intlong ,然后進行一些移位和屏蔽以從中提取目標位范圍。 這有可能提高效率,但是當目標范圍沒有越過數組的末尾但包含它們的字節對齊整數會時,有一些不幸的細節需要處理。

bitSize = 0時,最后丟棄多余位的方式無法正常工作,我認為支持這一點並不有趣,但可以通過將其作為特殊情況處理來輕松完成。 (1 << bitSize) - 1不同,我使用的方式確實適用於 32 位。

暫無
暫無

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

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