我正在解析一個二進制文件格式。它以一種自然適合c#的uint類型的方式編碼一個使用四個字節的整數。從字節數組中解開一個整數的習慣用c#是什麼?
什麼是實現這一功能的最C#/慣用方式:
uint ReadUint(byte[] buffer);
假定緩衝區包含4個元素。完整的答案可能會考慮由文件中的小/大端假設引起的一些常見字節順序,並記錄它選擇解析的一個或多個字節順序。
我正在解析一個二進制文件格式。它以一種自然適合c#的uint類型的方式編碼一個使用四個字節的整數。從字節數組中解開一個整數的習慣用c#是什麼?
什麼是實現這一功能的最C#/慣用方式:
uint ReadUint(byte[] buffer);
假定緩衝區包含4個元素。完整的答案可能會考慮由文件中的小/大端假設引起的一些常見字節順序,並記錄它選擇解析的一個或多個字節順序。
最基本的(但有點危險重新字節順序)爲:
return BitConverter.ToUInt32(buffer, 0);
比高於其他,移位是好的(根據你自己的回覆) - 或者你可以使用Jon的EndianBitConverter in MiscUtil,該手柄翻譯。
(編輯)
小尾數位移版本我在protobuf網用的是漂亮的,很多相同的版本 - 我剛剛看了他們按升序排列,使用按位(不是數字)此外:
return ((uint)buffer[0])
| (((uint)buffer[1]) << 8)
| (((uint)buffer[2]) << 16)
| (((uint)buffer[3]) << 24);
正如有人在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;
}
這解析維基百科聲稱在little-endian的方式設計了一個格式,就在i386上運行的.NET實現/ Vista的
假設你想讀他們的數據流(如您的代碼會建議) 我會說,這是非常接近的事實上的標準方式:
MemoryStream ms = new MemoryStream(new byte[100]);
BinaryReader br = new BinaryReader(ms);
uint q = br.ReadUInt32();
我通常會爲此使用BitConverter類。在你的情況下,BitConverter.ToUInt32()方法。
byte[] ba = new byte[]{ 0x10, 0xFF, 0x11, 0x01 } ;
var ui = BitConverter.ToUInt32(ba, 0);
簡單的方法是
int val = System.BitConverter.ToInt32(buffer, 0);
這使用當前系統的字節序,這可能會或可能不是你想要的是。
這個回覆實際上是一個擴展的評論(因此wiki)比較BitConverter的性能和bitshifting使用+ 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;
}
}
注意,按位|將比數字更簡單+ ...查看我的(更新)答案爲例。 – 2009-05-18 20:54:36
爲什麼會|比+更簡單嗎? – 2009-05-18 20:58:34
我的理解是,按位操作涉及的CPU比數學工作要少,因爲它只是應用了位掩碼。在「checked」上下文中可能會有額外的溢出檢查等(注意默認情況下C#是「unchecked」)。 – 2009-05-18 21:01:12