如何在 C# 中从字节 [] 中读取具有偏移量和位大小的 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
如何最有效地确保以下函数具有这些 return 值?:
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:
我也已经实现了自己的解决方案,我可以用它在此处获取此 post 的所有值。我只是对我的解决方案非常不满意,因为我不想每次都将数组传递给 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);
}
}
编辑:因为你在这里展示了你自己的尝试是一个非 code-golfed 答案:
//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;
}
如果您担心性能和数组分配,代码高尔夫答案实际上会更好。
这是一种可能的策略,读取字节 one-by-one 直到读取了足够的位,然后丢弃多余的部分。通过了两个测试用例,但 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
class(或其他技巧)读取整个 int
或 long
,然后进行一些移位和屏蔽以从中提取目标位范围.这有可能更有效,但有一些不幸的细节需要处理,当目标范围没有穿过数组的末尾,但包含它们的 byte-aligned 整数会。
当 bitSize = 0
时,最后丢弃多余位的方式无法正常工作,我认为支持它并不有趣,但可以通过将其作为特殊情况处理来轻松完成。与 (1 << bitSize) - 1
不同,我使用的方式确实适用于 32 位。
解决方案使用BitArray and BitConverter
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);
}
我需要一个将偏移量和位大小作为参数的函数,以从字节数组中读取 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
如何最有效地确保以下函数具有这些 return 值?:
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: 我也已经实现了自己的解决方案,我可以用它在此处获取此 post 的所有值。我只是对我的解决方案非常不满意,因为我不想每次都将数组传递给 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);
}
}
编辑:因为你在这里展示了你自己的尝试是一个非 code-golfed 答案:
//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;
}
如果您担心性能和数组分配,代码高尔夫答案实际上会更好。
这是一种可能的策略,读取字节 one-by-one 直到读取了足够的位,然后丢弃多余的部分。通过了两个测试用例,但 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
class(或其他技巧)读取整个 int
或 long
,然后进行一些移位和屏蔽以从中提取目标位范围.这有可能更有效,但有一些不幸的细节需要处理,当目标范围没有穿过数组的末尾,但包含它们的 byte-aligned 整数会。
当 bitSize = 0
时,最后丢弃多余位的方式无法正常工作,我认为支持它并不有趣,但可以通过将其作为特殊情况处理来轻松完成。与 (1 << bitSize) - 1
不同,我使用的方式确实适用于 32 位。
解决方案使用BitArray and BitConverter
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);
}