9

当我IsLittleEndianBitConverter. 我当然认为它应该在那里,我应该能够指定我喜欢的任何字节序。好吧,我的幸福并没有持续多久。花了一些时间才发现没有办法设置字段。该字段为readonly,并且仅true在静态构造函数中设置为:

static BitConverter()
{
    IsLittleEndian = true;
}

有趣的是,该字段实际上是在代码中使用的。例如ToInt32方法实现如下所示:

if (IsLittleEndian)
{
     return (((numRef[0] | (numRef[1] << 8)) | (numRef[2] << 0x10)) | (numRef[3] << 0x18));
}
return ((((numRef[0] << 0x18) | (numRef[1] << 0x10)) | (numRef[2] << 8)) | numRef[3]);

所以似乎ToInt32完全有能力处理小端和大端。

我的问题是:为什么有一段非常有用的代码已经实现并放在 FCL 中,但是没有办法使用它(当然,除非你开始弄乱反射)?仅仅是因为一些开发人员没有按时完成任务而半途而废吗?即使是这样,为什么代码不可用,但字段可用?我希望有一个很好的理由。

我想让自己清楚。我不需要关于如何处理大端值的解决方案。我确实有解决办法。解决方案实际上显示在我的问题中。

4

7 回答 7

6

不幸的是,该IsLittleEndian字段只是为了通知您。但是 Jon Skeets MiscUtil 库有一个不错的 EndianBitConverter,它支持小端和大端。还有字节序感知的 BinaryWriter/-Reader 类。

这是链接:http ://www.yoda.arachsys.com/csharp/miscutil/

编辑:对不起,但我没有更好的解释。我认为这应该已经包含在框架中,并且我猜代码当前就在那里,因此很容易将 Converter 移植到另一个架构中。

但是公开该功能比仅仅公开该字段要复杂一些。转换器是静态的,因此更改标志会有效地更改全局状态,并且在多线程场景中这将是灾难性的。要走的路可能是提供两个 BitConverter 对象,您可以在本地实例化和使用它们(这就是 MiscUtil 所做的)。这需要额外的类和/或接口,所以也许这是一个截止日期问题,暂时被放弃了。让我们希望它稍后会添加。

于 2011-06-20T04:10:23.620 回答
5

首先让我们确定该类BitConverter是专门为本地处理器的位转换而设计的。这就是为什么IsLittleEndian是只读的。因此,如果本地处理器是 little-endian,则它不支持与 big-endian 进行转换,反之亦然。

虽然我不知道省略支持一般字节序的原因,但对我来说最合乎逻辑的原因是性能。一个在整个框架中广泛用于其预期目的(与本机处理器的字节序转换)的类应该尽可能具有高性能。通过限制类的一般性,通过限制必须处理的情况来提高其性能。通过仅支持 little-endian 可能更快地进行测量

好的,现在我们进入问题的症结所在。如果类的整体设计只打算支持一个,为什么作者要包含处理小端和大端的代码?

同样,我们只能推测。但答案可能在于两个观察结果:

  • 引用的反汇编代码在IsLittleEndian 性能方面是不重要的情况
  • 编写可移植的代码,如果不影响性能,是一个很好的软件工程

您从该ToInt32方法复制的代码不重要的原因是它仅用于未对齐的内存。99% 的代码路径是位的直接不安全“memcpy”。

即使确实发生了从未对齐内存的转换,处理它的代码也比原始方法的效率低一个数量级。因此,额外的条件并不会真正影响性能。

最终结果是:

  • 该类因其有限的目的BitConverter尽可能高效
  • 的源代码BitConverter仍然可以移植到大端处理器架构
于 2011-06-30T04:28:33.787 回答
5

答案在于查看 BitConverter 类的参考源

相关摘录是:

        // This field indicates the "endianess" of the architecture.
        // The value is set to true if the architecture is
        // little endian; false if it is big endian.
#if BIGENDIAN
        public static readonly bool IsLittleEndian /* = false */;
#else
        public static readonly bool IsLittleEndian = true;
#endif

该标志由预处理器指令硬连线,因为编译特定版本框架的体系结构的字节序不会改变。

于 2014-07-23T11:39:02.630 回答
1

根据 MSDN 文档IsLittleEndian,它只是通知您(您的程序或 BitConverter 类)架构是 Little Endian 还是 Big Endian。我不认为除此之外还有其他用途。

于 2011-06-20T03:33:00.563 回答
0

它是根据建筑类型在内部设置的。

来自文档

“不同的计算机体系结构使用不同的字节顺序存储数据。“Big-endian”表示最高有效字节位于单词的左端。“Little-endian”表示最高有效字节位于单词的右端。”

编辑:

这是 c# 团队做出的设计决定。该函数能够从这两种类型转换,因为它可以在两种类型的系统上使用。作为开发人员,您可以自行转换它。

“...BitConverter 的所有方法都接受或返回 SYSTEM 字节序的字节数组...”

int i = BitConverter.ToInt32(byte[] inputdata);
(manipulate i)
return BitConverter.GetBytes(i);

“在数据永远不会离开您的应用程序范围的情况下,这实际上工作得很好。”

欲了解更多信息,请阅读这篇文章

于 2011-06-20T03:32:31.487 回答
0

请参阅http://snipplr.com/view/15179/adapt-systembitconverter-to-handle-big-endian-network-byte-ordering-in-order-to-create-number-types-from-bytes-and-viceversa /如果你想要一个允许你设置字节序的实现。

于 2011-06-20T04:02:30.307 回答
0

我很确定他们将其设置为true不可能,false因为所有版本Windows都是 little-endian

现在,他们if (IsLittleEndian)在一个从不设置IsLittleEndian任何东西的课程中做的问题true很可能是一个以防万一的情况。这样,如果确实需要为 big-endian 编译 .NET BCL,那么一个简单的#if/#else围绕该分配就足够了,而不必编写新代码。

我敢打赌 Mono 会false为某些操作系统和架构设置它。

编辑:我是对的。Mono 执行以下操作。从技术上讲,其他代码都不需要添加,只是由于版权问题,他们不得不在 Mono 中以不同的方式编写所有代码。

public static readonly bool IsLittleEndian = AmILittleEndian ();

static unsafe bool AmILittleEndian ()
{
  // binary representations of 1.0:
  // big endian: 3f f0 00 00 00 00 00 00
  // little endian: 00 00 00 00 00 00 f0 3f
  // arm fpa little endian: 00 00 f0 3f 00 00 00 00
  double d = 1.0;
  byte *b = (byte*)&d;
  return (b [0] == 0);
}
于 2011-06-20T04:37:25.023 回答