12

Is C# ever Endian sensitive, for example, will code such as this:

int a = 1234567;
short b = *(short*)&i;

always assign the same value to b. If so, what value will it be?

If not, what good ways are there to deal with endianness if code with pointers in?

Martin
  • 12,469
  • 13
  • 64
  • 128
  • 1
    Eeer, you can't do pointer fun in C# :) – cwap Feb 11 '10 at 21:40
  • 4
    @cwap: If you want to get dirty you can work with pointers in `unsafe` blocks. – Restore the Data Dumps Feb 11 '10 at 21:41
  • 2
    You can with an unsafe block. It's a pretty academic question, because as far as I know there's no implementation of C# on a differently-endian architecture, but interesting nonetheless. – Ryan Brunner Feb 11 '10 at 21:41
  • 2
    Mono probably has to deal with this stuff. – Anon. Feb 11 '10 at 21:42
  • 1
    You can do pointers in C#, and sometimes I need to for efficiency :( – Martin Feb 11 '10 at 21:42
  • Ye, didn't consider those, as Ive never really used them "IRL" :) – cwap Feb 11 '10 at 21:43
  • 1
    The xbox is the opposite endianness to normal PCs if I remember correctly. Which is pretty important since this is for an XNA networking library (ie. designed for xbox and PC, thus it must run on both). Also, just because there isn't a release of .net for opposite endianness yet doesn't mean there won't ever be. – Martin Feb 11 '10 at 21:44
  • 1
    the .net microframework runs on all sorts of exotic embedded processors – pm100 Feb 11 '10 at 22:17
  • "You can do pointers in C#, and sometimes I need to for efficiency" - there's a fix for that, its called C :) – gbjbaanb Feb 16 '10 at 00:26
  • Loads of pointer stuff happening in [the source for `System.BitConverter`](https://referencesource.microsoft.com/#mscorlib/system/bitconverter.cs). – Wai Ha Lee Mar 19 '19 at 09:25

4 Answers4

15

C# doesn't define the endianness. In reality, yes it will probably always be little-endian (IIRC even on IA64, but I haven't checked), but you should ideally check BitConverter.IsLittleEndian if endianness is important - or just use bit-shifting etc rather than direct memory access.

To quote a few lines from protobuf-net (a build not yet committed):

WriteInt64(*(long*)&value);
if (!BitConverter.IsLittleEndian)
{   // not fully tested, but this *should* work
    Reverse(ioBuffer, ioIndex - 8, 8);
}

i.e. it checks the endianness and does a flip if necessary.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Right, so basically work assuming little endian (since that's the most common case) and do a swap before doing direct memory access if necessary? – Martin Feb 11 '10 at 21:45
  • @Martin - indeed. Optimise (if appropriate / necessary) for what you *expect*, but ideally support either. Or at least throw an obvious exception at some point. – Marc Gravell Feb 11 '10 at 23:02
  • Of course, I could put compiler blocks in and have the conditionals at compile time. Since this is something that isn't going to change during the execution of the program ;) – Martin Feb 11 '10 at 23:23
  • @Martin - are you always compiling on the same machine that will do the running? – Marc Gravell Feb 12 '10 at 05:13
  • No, in fact one of the machines is an xbox which of course can't do compilation. But does that matter, if I manually set the target platform endianness and compile? – Martin Feb 12 '10 at 13:28
  • @Martin - fine, but *check* it during initialization. i.e. in `Main()` or whatever, **verify** that `BitConverter.IsLittleEndian` is what the build expects. – Marc Gravell Feb 12 '10 at 16:37
  • @Marc: I'm pretty sure @Martin is right on that. PowerPC processors are big endian AFAIK. – Mehrdad Afshari Feb 13 '10 at 19:35
6

Yes, I believe that code is endian-sensitive. The value of b will be the least-significant bytes on a little-endian processor, and the most-significant bytes on a big-endian processor. To make this simpler to see, let's switch to hex:

using System;

class Test
{
    unsafe static void Main()
    {
        int a = 0x12345678;
        short b = *(short*)&a;
        Console.WriteLine(b.ToString("x"));
    }
}

On my x86 box, that prints "5678" showing that the least-significant bytes were at the "start" of the vaue of a. If you run the same code on a processor running in big-endian mode (probably under Mono) I'd expect it to print "1234".

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

As far as I can tell, neither the C# nor the Common Language Infrastructure specifications have endianness requirements for pointer-based bitwise and mathematical operations. The CLI does state that binary data stored in a MSIL executable file must be in little endian format. And the general drift of the documents would indicate that code shouldn't be dependent on any specific memory representation (including packed or unpacked arrays, etc.) except under special circumstances.

Jeffrey L Whitledge
  • 58,241
  • 9
  • 71
  • 99
-3

You really shouldn't be doing pointer swizzling in C#. You should try compiling your code before asking what it will do.

Anon.
  • 58,739
  • 8
  • 81
  • 86
  • 3
    I know what it does on my particular machine. However, I want to know if it will do the same on _all_ machines. It would be pretty bad practice to run it on my machine and just assume, especially given that I know this is a hardware sensitive issue. Please try to actually answer the question? – Martin Feb 11 '10 at 21:42
  • As mentioned above, pointers are perfectly appropriate in unsafe blocks. – Ryan Brunner Feb 11 '10 at 21:42
  • The answer is "You shouldn't". Cast from `int` to `short` if you want to convert stuff, there is really no reason to do pointer tricks in C#. – Anon. Feb 11 '10 at 21:43
  • 1
    "You shouldn't" eh? Do you mean that in the same way as "You shouldn't use goto"? – Restore the Data Dumps Feb 11 '10 at 21:47
  • There is, for example in this case I'm packing 7 bit integers into a 64 bit integer with 1 bit padding. Using pointers is somewhat easier... – Martin Feb 11 '10 at 21:47
  • Is there some reason you can't just use an array of bytes? – Anon. Feb 11 '10 at 21:49
  • Yes, the xbox gc is unfortunately rather slow, allocating is generally a bad idea once the game has started, since it would stutter every so often (ie. every GC). I might consider some kind of byte array pooling, but for now I'm designing the system and considering all possibilities – Martin Feb 11 '10 at 21:51