为什么当开始索引被转换为工作的类型的大小整除时,BitConverter使用的快捷方式

本文关键字:BitConverter 快捷方式 类型 索引 开始 转换 为什么 工作 | 更新日期: 2023-09-27 17:49:40

我最近一直在研究BitConverter是如何工作的,从阅读其他SO问题中,我读到它需要一个"快捷方式",当开始索引被转换为类型的大小可除时,它可以将索引上的字节指针转换为指向被转换为并取消引用的类型的指针。

以ToInt16为例的源代码:

public static unsafe short ToInt16(byte[] value, int startIndex) {
     if( value == null)  {
          ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
     }
     if ((uint) startIndex >= value.Length) {
          ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
     }
     if (startIndex > value.Length -2) {
          ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
     }
     Contract.EndContractBlock();
     fixed( byte * pbyte = &value[startIndex]) {
          if( startIndex % 2 == 0) { // data is aligned 
              return *((short *) pbyte);
          }
          else {
              if( IsLittleEndian) { 
                   return (short)((*pbyte) | (*(pbyte + 1) << 8)) ;
              }
              else {
                   return (short)((*pbyte << 8) | (*(pbyte + 1)));                        
              }
          }
     }
}

我的问题是,为什么不管机器的端序如何,它都能工作,为什么当数据不对齐时,它不使用相同的机制?

一个澄清的例子:

我在buffer中有一些字节,我知道是大端格式,我想从数组中读取一个短值,比如索引5。我还假设我的机器,因为是Windows,所以使用小端序。

我将像这样使用BitConverter,通过将我的字节顺序切换为小端序:

BitConverter.ToInt16(new byte[] { buffer[6], buffer[5] })

假设代码采用快捷方式,它将做我想要的:只是按照提供的顺序转换字节并返回值。但如果它没有快捷代码,它会不会再次反转字节顺序,给我错误的值?或者如果我这样做:

BitConverter.ToInt16(new byte[] { 0, buffer[6], buffer[5] }, 1)

会不会给我一个错误的值,因为索引不能被2整除?

另一种情况:

假设我有一个字节数组,其中包含一个短的地方,我想以小端序格式提取,但从奇数偏移量开始。对BitConverter的调用不会颠倒字节的顺序吗?IsLittleEndian是真的,索引没有对齐,从而给我一个不正确的值?

为什么当开始索引被转换为工作的类型的大小整除时,BitConverter使用的快捷方式

代码避免了处理器上不允许不对齐数据访问的硬件异常,即总线错误。这非常昂贵,它通常由内核代码解决,内核代码将总线访问分开并将字节粘合在一起。在编写这段代码的时候,这种处理器仍然非常普遍,这是MIPS等RISC设计流行的尾声。老旧的ARM内核和Itanium是另一个例子,. net版本已经为它们发布了。

对于没有问题的处理器,比如英特尔/AMD内核,这几乎没有什么区别。

代码使用IsLittleEndian仅仅是因为它对单个字节进行索引。这当然使得字节顺序很重要。

在大多数体系结构中,访问未按适当边界对齐的数据会影响性能。在x86上,CPU将允许您从未对齐的地址中读取,但这会影响性能。在某些体系结构中,您将获得操作系统将捕获的CPU错误。

我猜让CPU修复读取未对齐数据的成本大于读取单个字节并进行移位/或操作的成本。此外,代码现在可以移植到那些未对齐读取会导致错误的平台上。

为什么不管机器的端序如何都可以工作?

该方法对byte s进行重新解释,假设它们是在具有相同端序的环境中产生的。也就是说,端序既影响输入字节在数组中的排列顺序,也影响输出short中需要排列的字节顺序。

当机器是大端序时,为什么不使用相同的机制?

这是一个很好的观察,作者为什么不进行强制转换并不是很明显。我认为其背后的原因是,如果您将具有奇数值的pbyte转换为short*,则对short的后续访问将是未对齐的。这需要一个特殊的操作码来防止一些平台在未对齐访问时产生的硬异常。