views:

413

answers:

4

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?

A: 

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

Anon.
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
As mentioned above, pointers are perfectly appropriate in unsafe blocks.
Ryan Brunner
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.
"You shouldn't" eh? Do you mean that in the same way as "You shouldn't use goto"?
Jason Punyon
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
Is there some reason you can't just use an array of bytes?
Anon.
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
+14  A: 

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
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
@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
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
@Martin - are you always compiling on the same machine that will do the running?
Marc Gravell
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
@Martin - fine, but *check* it during initialization. i.e. in `Main()` or whatever, **verify** that `BitConverter.IsLittleEndian` is what the build expects.
Marc Gravell
@Marc: I'm pretty sure @Martin is right on that. PowerPC processors are big endian AFAIK.
Mehrdad Afshari
It's good advice from Marc nonetheless
Martin
+5  A: 

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  A: 

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