BinaryReader.ReadUInt64() 的效率

Efficiency in BinaryReader.ReadUInt64()

当我在 .NET BinaryReader 中遇到这段代码时,我只是想优化一些代码 class:

[CLSCompliant(false)]
[__DynamicallyInvokable]
public virtual ulong ReadUInt64()
{
  this.FillBuffer(8);
  return (ulong) (uint) ((int) this.m_buffer[4] | (int) this.m_buffer[5] << 8 | (int) this.m_buffer[6] << 16 | (int) this.m_buffer[7] << 24) << 32 | (ulong) (uint) ((int) this.m_buffer[0] | (int) this.m_buffer[1] << 8 | (int) this.m_buffer[2] << 16 | (int) this.m_buffer[3] << 24);
}

我想知道为什么 ulong 被分成两部分移动然后合并,而不是只移动 0,8,16,..,56。

我还想了解这里使用的多重转换。

编辑:当我在安装了 ReSharper 的 VS2013 中键入此内容时,它显示如下:

如您所见,第二个ulong变暗了,这意味着它甚至没有被使用。似乎缺少一对括号。这样对吗?

首先,让我们以更易读的形式重写:

(ulong)(uint)(
    (int) this.m_buffer[4]       | 
    (int) this.m_buffer[5] << 8  |
    (int) this.m_buffer[6] << 16 |
    (int) this.m_buffer[7] << 24)
<< 32 | 
(ulong)(uint)(
    (int) this.m_buffer[0]       |
    (int) this.m_buffer[1] << 8  | 
    (int) this.m_buffer[2] << 16 | 
    (int) this.m_buffer[3] << 24)

现在很清楚这是做什么了。

它将低 32 位和高 32 位组合成两个单独的 uint 值(通过将字节转换为 int 后移动字节),然后转换两个结果 int ulong 的值,将高 32 位移动 32,最后将它们组合在一起得到结果。

之所以这样做,是因为移动 32 位值比移动 64 位值更快。如果代码将所有字节转换为 ulong 然后移动它们,它会更慢。

另请注意,它组合字节的顺序适用于 "little endian" 格式。

唯一明显奇怪的是第一个演员 (ulong)(uint),可能只是 (ulong)。如果你删除所有不必要的转换,它看起来像这样:

(ulong)(
    buffer[4]       |
    buffer[5] << 8  |
    buffer[6] << 16 |
    buffer[7] << 24)
<< 32 |
(uint)(
    buffer[0]       |
    buffer[1] << 8  |
    buffer[2] << 16 |
    buffer[3] << 24);

现在您可能想知道为什么不能只转换为 ulong 而不是 uint

这个问题的答案如下。假设代码是这样的:

(ulong)(
    buffer[4]       |
    buffer[5] << 8  |
    buffer[6] << 16 |
    buffer[7] << 24)
<< 32 |
(ulong)(         // This seems more natural...
    buffer[0]       |
    buffer[1] << 8  |
    buffer[2] << 16 |
    buffer[3] << 24);

表达式的第一部分使用 ulong.operator<<() 转换为 (ulong)。这个returns一个(ulong).

但是表达式的第二部分没有移位,当它与第一个表达式进行 OR 运算时会提示编译器警告:

警告 CS0675:按位或运算符用于符号扩展操作数;首先考虑转换为较小的无符号类型

Eric Lippert 有 a blog about this warning 你应该读一读。

无论如何,因为在第一部分转换为 (ulong) 和第二部分转换为 (uint) 时看起来很奇怪,我相当确定他们放入了完整的显式转换以防止混淆reader.

的部分