// 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.
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.
–
–
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
–
–
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.
–
–
–
–
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);
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.