在.NET中反转字节顺序
在下面的代码中,为什么X和Y的值与我直观的想法不同 如果将字节0-7写入缓冲区,那么产生的long不应该具有相同顺序的字节吗?它就像是在以相反的顺序读取长值在.NET中反转字节顺序,.net,endianness,.net,Endianness,在下面的代码中,为什么X和Y的值与我直观的想法不同 如果将字节0-7写入缓冲区,那么产生的long不应该具有相同顺序的字节吗?它就像是在以相反的顺序读取长值 x 0x0706050403020100 long y 0x0706050403020100 long z 0x0001020304050607 long MemoryStream ms = new MemoryStream(); byte[] buffer = new byte[] { 0x00, 0
x 0x0706050403020100 long
y 0x0706050403020100 long
z 0x0001020304050607 long
MemoryStream ms = new MemoryStream();
byte[] buffer = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
ms.Write(buffer, 0, buffer.Length);
ms.Flush();
ms.Position = 0;
BinaryReader reader = new BinaryReader(ms);
long x = reader.ReadInt64();
long y = BitConverter.ToInt64(buffer, 0);
long z = BitConverter.ToInt64(buffer.Reverse<byte>().ToArray<byte>(), 0);
byte[] xbytes = BitConverter.GetBytes(x);
byte[] ybytes = BitConverter.GetBytes(y);
byte[] zbytes = BitConverter.GetBytes(z);
这是错误的。如果我的电脑是big endian,为什么会发生这种情况
- 这是一台Windows 7 64位计算机
- 英特尔Core2四核Q9400 2.66GHz LGA 775 95W四核处理器型号BX80580Q9400
- 超级微型MBD-C2SBX+-O LGA 775英特尔X48 ATX英特尔主板
False
506097522914230528
您在一台计算机上,整数首先存储在最低有效字节。BinaryReader采用较小的尾端顺序:如果您关心字节的尾端顺序,Jon Skeet编写了一个类,允许您在进行转换时选择尾端顺序 参见是设计上的小端点。从文件中: BinaryReader以little-endian格式读取此数据类型 事实上,我们可以使用Reflector检查源代码中的
BinaryReader.ReadInt64
public virtual long ReadInt64() {
this.FillBuffer(8);
uint num = (uint) (((this.m_buffer[0] |
(this.m_buffer[1] << 0x08)) |
(this.m_buffer[2] << 0x10)) |
(this.m_buffer[3] << 0x18));
uint num2 = (uint) (((this.m_buffer[4] |
(this.m_buffer[5] << 0x08)) |
(this.m_buffer[6] << 0x10)) |
(this.m_buffer[7] << 0x18));
return (long) ((num2 << 0x20) | num);
}
因此,我们在这里看到的是,如果startIndex
与零模八相等,则直接从地址numRef
开始的八个字节进行强制转换。由于对齐问题,本案例专门处理。代码行
return *(((long *) numRef));
直接翻译成
ldloc.0 ;pushes local 0 on stack, this is numRef
conv.i ;pop top of stack, convert to native int, push onto stack
ldind.i8 ;pop address off stack, indirect load from address as long
ret ;return to caller, return value is top of stack
因此我们看到,在本例中,键是ldind.i8
指令。CLI不知道底层计算机的终结性。它让JIT编译器处理这个问题。在小端机器上,ldind.i8
将把较高的地址加载到较高的有效位,而在大端机器上,ldind.i8
将把较高的地址加载到较低的有效位。因此,在这种情况下,endianness被正确处理
在另一种情况下,您可以看到对静态属性BitConverter.IsLittleEndian
进行了显式检查。在小端数的情况下,缓冲区被解释为小端数(这样内存{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}
被解释为长0x07060504030100
),在大端数的情况下,缓冲区被解释为大端数(这样内存{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}
被解释为长0x0001020304050607
)。因此,对于位转换器
来说,这一切都取决于欠旋转机器的端部。我注意到您使用的是Windows 7 x64上的英特尔芯片。英特尔芯片是小端的。我注意到,在Reflector中,位转换器的静态构造函数定义如下:
static BitConverter() {
IsLittleEndian = true;
}
这是在我的Windows Vista x64计算机上。(比如说,在XBox 360上的.NET CF上可能会有所不同。)Windows 7 x64没有任何不同的理由。因此,您确定BitConverter.IsLittleEndian
是false
?它应该是true
,因此您看到的行为是正确的。您完全确定BitConverter.IsLittleEndian返回false吗
如果在使用它的任何方法之前通过调试器监视对其进行检查,那么即使它应该返回true,也可能会得到false
通过代码读取值以完全确定。
另请参见它只是:
if (BitConverter.IsLittleEndian == true) Array.Reverse(var);
位转换器
使用它所运行的机器的端度。要确保使用大端数字,请使用IPAddress.HostToNetworkOrder
。例如:
IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer))
为您添加了搜索标签:)您能给出机器的规格(处理器、mb、O/S)吗?这是一个Intel Core 2,Windows 7。我还应该补充一点,BitConverter.IsLittleEndian返回false。您可以执行以下操作吗:byte[]buffer=new byte[]{0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};长y=位转换器.ToInt64(缓冲区,1)
并报告y
的值。请注意,buffer
比您给出的定义多了一个字节。我无法访问BitConverter.IsLittleEndian
为false的机器。杰森:我在罚单的编辑2中回答了你的问题。作为一个非.NET人员,我对这个问题感到惊讶。我本来希望.NET能像Java一样将程序员与endianness隔离开来。机器的endianness是不相关的,CLI假设endianness很小,但事实并非如此。Java也不例外。颠倒字节顺序太贵了。最近没什么问题,little endian赢了。BitConverter.IsLittleEndian返回False这是我在stackoverflow上找到的最有用的答案。感谢您一直深入了解IL说明的行为。我完全搞不懂为什么某段代码在显式endian更正发生之前工作。那么有没有办法强制读取反转数组(发出前导零,反转后变为尾随零)。鉴于字节通常来自定义了规格的文件,我一直不明白为什么这些转换必须依赖于机器的端度,而不是,你知道,一个布尔参数……关于为什么这一部分会有用的任何解释?我也很好奇这一点。这段代码似乎解决了我遇到的问题,但我想确定它实际上做了什么。
static BitConverter() {
IsLittleEndian = true;
}
if (BitConverter.IsLittleEndian == true) Array.Reverse(var);
IPAddress.HostToNetworkOrder(BitConverter.ToInt64(buffer))