2008-10-20 10 views
52

In der Dokumentation von Hardware, die wir es über UDP/IP zu steuern, fand ich das folgende Fragment:C# Little Endian oder Big Endian?

In diesem Kommunikationsprotokoll, DWORD ein 4-Byte-Daten ist, WORD ein 2-Byte-Daten ist, BYTE ist ein einzelnes Byte Daten. Das Speicherformat ist Little Endian, nämlich 4 Byte (32 Bit) Daten werden gespeichert als: d7-d0, d15-d8, d23-d16, d31-d24; Doppelbyte (16 Bit) Daten werden gespeichert als: d7-d0, d15-d8.

Ich frage mich, wie sich das in C# übersetzt? Muss ich Sachen konvertieren, bevor ich sie sende? Zum Beispiel, wenn ich über eine 32-Bit-Ganzzahl oder eine 4-stellige Zeichenfolge senden möchte?

Antwort

66

C# selbst definiert nicht die Endianess. Wenn Sie jedoch in Byte konvertieren, treffen Sie eine Auswahl. Die BitConverter Klasse hat ein IsLittleEndian Feld, um Ihnen zu sagen, wie es sich verhält, aber es gibt die Wahl nicht. Das gleiche gilt für BinaryReader/BinaryWriter.

Meine MiscUtil Bibliothek verfügt über eine EndianBitConverter-Klasse, mit der Sie die Endianess definieren können; Es gibt ähnliche Entsprechungen für BinaryReader/Writer. Ich habe Angst, aber sie sind trivial :)

(EndianBitConverter hat auch ein Stück Funktionalität, die nicht in der normalen BitConverter, die Konvertierungen in-Place in einem Byte-Array zu tun ist .)

+2

Denken Sie auch daran, in C# ist es möglich, Werte direkt zu kopieren, z. * ptr = Wert; In diesem Fall sollten Sie sich Gedanken über die Byte-Reihenfolge der Computerarchitekturen machen. – markmnl

10

Re little-endian, die kurze Antwort (zu tun brauche ich) ist "wahrscheinlich nicht, aber es hängt von Ihrer Hardware ab". Sie können überprüfen mit:

bool le = BitConverter.IsLittleEndian; 

Je nachdem, was dies sagt, möchten Sie möglicherweise Teile Ihrer Puffer umzukehren. Alternativ hat Jon Skeet spezifische Endian-Konverter here (suchen Sie nach EndianBitConverter).

Beachten Sie, dass Itanium (zum Beispiel) Big-Endian sind. Die meisten Intels sind Little-Endian.

Zu den spezifischen UDP/IP ...?

+0

... Ist jemand .net auf itanium mit? – SingleNegationElimination

+0

hmm. Die Grundlagenforschung, die ich gerade durchgeführt habe, scheint darauf hinzudeuten, dass Windows immer ein Little Endian ist (Itanium kann beide Endianheiten unterstützen). BitConverter.IsLittleEndian scheint also * immer * wahr zu sein, es sei denn, du liebst etwas wie Mono auf einem Big-Endian-Linux auf Itanium. Siehe http://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx – piers7

+0

Einer der Kommentare schlägt vor, XNA auf Xbox kann Big-Endian sein; Ich habe nicht überprüft: http://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx#426591 –

3

Sie müssen wissen über Netzwerk-Byte-Reihenfolge sowie CPU-Endian-Ness.

In der Regel für TCP/UDP-Kommunikation, konvertieren Sie immer Daten in Netzwerk-Byte-Reihenfolge mit der htons-Funktion (und ntohs und ihre zugehörigen Funktionen).

Normalerweise Netzwerk-Reihenfolge ist Big-Endian, aber in diesem Fall (aus irgendeinem Grund!) Die Kommunikation ist wenig Endian, so dass diese Funktionen nicht sehr nützlich sind. Dies ist wichtig, da Sie nicht davon ausgehen können, dass die von Ihnen implementierten UDP-Kommunikationen anderen Standards folgen, es macht auch das Leben schwierig, wenn Sie eine Big-Endian-Architektur haben, da Sie einfach nicht alles mit htons umhüllen können :-(

wenn Sie jedoch von einer Intelen x86-Architektur kommen, dann bist du schon little-endian, so dass nur die Daten ohne Konvertierung senden.

41

Sie auch

IPAddress.NetworkToHostOrder(...) 

Für kurzes, int verwenden können oder lang.

0

Wenn Sie das Parsen und Leistung ist nicht kritisch, sollten Sie diesen sehr einfachen Code:

private static byte[] NetworkToHostOrder (byte[] array, int offset, int length) 
{ 
    return array.Skip (offset).Take (length).Reverse().ToArray(); 
} 

int foo = BitConverter.ToInt64 (NetworkToHostOrder (queue, 14, 8), 0); 
0

Ich spiele um mit gepackten Daten in UDP-Multicast und ich brauchte etwas UInt16 Bytes neu zu ordnen, da ich bemerkte ein Fehler in der Paketheader (Wireshark), so habe ich folgendes:

private UInt16 swapOctetsUInt16(UInt16 toSwap) 
    { 
     Int32 tmp = 0; 
     tmp = toSwap >> 8; 
     tmp = tmp | ((toSwap & 0xff) << 8); 
     return (UInt16) tmp; 
    } 

bei UInt32,

private UInt32 swapOctetsUInt32(UInt32 toSwap) 
    { 
     UInt32 tmp = 0; 
     tmp = toSwap >> 24; 
     tmp = tmp | ((toSwap & 0xff0000) >> 8); 
     tmp = tmp | ((toSwap & 0xff00) << 8); 
     tmp = tmp | ((toSwap & 0xff) << 24); 
     return tmp; 
    } 

Dies ist nur zum Testen

private void testSwap() { 
     UInt16 tmp1 = 0x0a0b; 
     UInt32 tmp2 = 0x0a0b0c0d; 
     SoapHexBinary shb1 = new SoapHexBinary(BitConverter.GetBytes(tmp1)); 
     SoapHexBinary shb2 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt16(tmp1))); 
     Debug.WriteLine("{0}", shb1.ToString()); 
     Debug.WriteLine("{0}", shb2.ToString()); 
     SoapHexBinary shb3 = new SoapHexBinary(BitConverter.GetBytes(tmp2)); 
     SoapHexBinary shb4 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt32(tmp2))); 
     Debug.WriteLine("{0}", shb3.ToString()); 
     Debug.WriteLine("{0}", shb4.ToString()); 
    } 

von dem Ausgang war:

0B0A: {0} 
    0A0B: {0} 
    0D0C0B0A: {0} 
    0A0B0C0D: {0}