BitConverter 类中 IsLittleEndian 的用例有哪些?

发布于 2024-11-15 23:43:13 字数 840 浏览 6 评论 0原文

当我在 BitConverter 中发现 IsLittleEndian 字段时,我非常高兴。我认为它当然应该在那里,并且我应该能够指定我喜欢的任何字节序。好吧,我的幸福并没有持续多久。花了一些时间才发现没有办法设置字段。 该字段是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 中,但无法使用它(当然,除非您开始搞乱反射)?难道只是因为一些开发人员没有按时完成任务而半途而废吗?即使是这样,为什么代码不可用,但字段可用? 我希望这有一个充分的理由。

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

I was so happy when I discovered IsLittleEndian field in BitConverter. I thought of course it should be there and I should be able to specify whatever endian I like. Well, my happiness didn’t last long. Spent some time till found out that there is no way to set the field.
The field is readonly, and it is only set to true in static constructor:

static BitConverter()
{
    IsLittleEndian = true;
}

It is funny that the field is actually used in the code. For example ToInt32 method implementation looks like this:

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]);

So seems like the ToInt32 is perfectly capable to handle both little and big endians.

My question is: how come there is very useful piece of code that is already implemented and sitting there in the FCL, but there is no way to use it (unless you start messing with reflection of course)? Is it just because some developers didn’t meet the deadline and left the job half-done? Even if so, why the code is not available, but the field is?
I hope there is a good reason for this.

I want to make myself clear. I don't need a solution on how to handle big-endian values. I do have a solution. The solution is actually shown in my question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

机场等船 2024-11-22 23:43:13

答案在于查看 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

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

The answer lies in looking at the reference source for the BitConverter class.

The relevant extract is:

        // 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

The flag is hard-wired by the preprocessor directive because the endian-ness of the architecture for which a particular version of the framework is compiled will not change.

柠北森屋 2024-11-22 23:43:13

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

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

编辑:抱歉,但我没有更好的解释。我认为这应该包含在框架中,并且我猜代码当前就在那里,这样就可以轻松地将转换器移植到另一个架构中。

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

Unfortunately the IsLittleEndian field is just there to inform you. But Jon Skeets MiscUtil library has a nice EndianBitConverter, that supports little and big endian. There are also endian-aware BinaryWriter/-Reader classes.

Here is the link: http://www.yoda.arachsys.com/csharp/miscutil/

Edit: sorry but I don't have a better explanation. I think that this should have been included in the framework and I guess the code is currently there, so that it is easy to port the Converter to another architecture.

But exposing that functionality is a tad more complex than just making the field public. The converter is static, so changing the flag effectively changes global state and in a multi-threaded scenario this would be disastrous. The way to go is probably to provide two BitConverter objects that you can instantiate and use locally (that's what MiscUtil does). This requires additional classes and/or interfaces, so maybe it was a deadline issue and just got dropped for the time being. Let's hope it is added some time later.

与之呼应 2024-11-22 23:43:13

首先,我们确定类 BitConverter 是专门为仅适用于本地处理器的位转换而设计的。这就是 IsLittleEndian 是只读的原因。因此,如果本地处理器是小尾数法,则它不支持与大尾数法之间的转换,反之亦然。

尽管我不知道省略对一般字节顺序支持的原因,但对我来说最合乎逻辑的原因是性能。出于其预期目的(在本机处理器的字节顺序之间进行转换)而在整个框架中广泛使用的类应该尽可能具有高性能。通过限制类的通用性,可以通过限制必须处理的情况来提高其性能。通过仅支持小尾数,它可能可测量得更快

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

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

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

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

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

最终结果是:

  • BitConverter 类对于其有限的用途而言尽可能高效
  • BitConverter 的源代码仍然可以移植到大型-字节序处理器架构

First let's establish that the class BitConverter is specifically designed for bit conversion for the local processor only. That is why the IsLittleEndian is read-only. As a result, it does not support converting to or from big-endian if the local processor is little-endian and vice versa.

Although I do not know the reasoning for omitting support for general endianness, the most logical reason to me is performance. A class that is widely used throughout the framework for its intended purpose (conversion to and from the native processor's endianness), should be as performant as possible. By limiting the generality of the class, its performance is improved by restricting the cases that must be handled. By only supporting little-endian it is likely measurable faster.

OK, so now we get to the crux of the question. Why would the authors include code to handle both little-endian and big-endian if the overall design of the class only intends to support one?

Again, we can only speculate. But the answer likely rests in two observations:

  • the disassembled code that refers to IsLittleEndian is an unimportant case performance-wise
  • writing portable code, if it doesn't affect performance, is a good software engineering

The reason that that the code you copied from the ToInt32 method is unimportant, is because it is only used for unaligned memory. The 99% code-path is a direct unsafe "memcpy" of the bits.

Even to the extent that converting from unaligned memory does occur, the code that handles it is an order of magnitude less efficient that the raw method. So an extra condition doesn't really hurt performance.

The net result is:

  • The BitConverter class is as efficient as possible for its limited purpose
  • The source-code for BitConverter is nevertheless portable to big-endian processor architectures
时光沙漏 2024-11-22 23:43:13

根据MSDN文档 IsLittleEndian 只是通知您(您的程序或 BitConverter 类)体系结构是小端还是大端。我不认为除此之外还有其他用途。

According to the MSDN documentation IsLittleEndian it's meerly to inform you (your program or the BitConverter Class) of whether or not the architecture is Little or Big Endian. I don't that there is an intended use outside of that.

烟酉 2024-11-22 23:43:13

它是根据架构类型在内部设置的。

来自文档

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

编辑:

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

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

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

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

有关详细信息,请阅读本文

it's set internally based on the achitecture type.

from the docs:

"Different computer architectures store data using different byte orders. "Big-endian" means the most significant byte is on the left end of a word. "Little-endian" means the most significant byte is on the right end of a word."

Edit:

This was a design decision made by the c# team. The function is capable of converting from both types because it can be used on both types of systems. it is up to you as the developer to convert it otherwise.

"...All methods of BitConverter accept or return byte arrays in SYSTEM endian order..."

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

"In the case where the data never leaves the confines of your application, this actually works fine."

For more information read this article.

﹉夏雨初晴づ 2024-11-22 23:43:13

我很确定他们将其设置为true,不可能false,因为所有版本的 Windows 均为小端字节序

现在,他们在一个从未将 IsLittleEndian 设置为 true 以外的任何内容的类中执行 if (IsLittleEndian) 的问题很可能只是 -以防万一。这样,如果确实需要为大尾数法编译 .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);
}

I'm pretty sure they set it to true with no possibility of false because all versions of Windows are little-endian.

Now, the issue of them doing if (IsLittleEndian) in a class that never sets IsLittleEndian to anything other than true is most likely a just-in-case scenario. This way if there ever does need to be a compile of the .NET BCL for big-endian, a simple #if/#else around that one assignment will suffice, rather than having to also write new code.

I bet Mono sets it false for some operating systems and architectures.

Edit: And I was right. Mono does the following. Technically none of the other code would need additions, except that they had to write everything differently in Mono due to copyright issues.

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文