Marshalling einer big-endian-byte-Sammlung in ein struct, um pull-out-Werte
Es ist eine aufschlussreiche Frage über das Lesen eines C/C++ - Datenstruktur in C# aus einem byte-array, aber ich Schaffe es nicht, den code an die Arbeit für meine Sammlung von big-endian (network-byte-order) Byte. (EDIT: Hinweis, dass mein real struct hat mehr als nur ein Feld.) Gibt es eine Möglichkeit, Marschall der bytes in einem big-endian-version der Struktur, und ziehen Sie dann die Werte in die endianness des Rahmens (das dem host, das ist in der Regel little-endian)?
(Beachten Sie, dass die Umkehrung der Byte-array wird nicht Arbeit - jeder Wert-bytes muss umgedreht werden, die nicht geben Sie die gleiche Sammlung wie eine Umkehr aller bytes.)
Diese sollten zusammenfassen, was ich bin auf der Suche nach (LE=LittleEndian, BE=BigEndian):
void Main()
{
var leBytes = new byte[] {1, 0, 2, 0};
var beBytes = new byte[] {0, 1, 0, 2};
Foo fooLe = ByteArrayToStructure<Foo>(leBytes);
Foo fooBe = ByteArrayToStructureBigEndian<Foo>(beBytes);
Assert.AreEqual(fooLe, fooBe);
}
[StructLayout(LayoutKind.Explicit, Size=4)]
public struct Foo {
[FieldOffset(0)]
public ushort firstUshort;
[FieldOffset(2)]
public ushort secondUshort;
}
T ByteArrayToStructure<T>(byte[] bytes) where T: struct
{
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(T));
handle.Free();
return stuff;
}
T ByteArrayToStructureBigEndian<T>(byte[] bytes) where T: struct
{
???
}
Andere hilfreiche links:
Byte der Struktur und auf endian betrifft
Ein wenig mehr auf bytes und endianness (byte-Reihenfolge)
Read binary-Dateien effizienter mit C#
Unsichere und Lesen von Dateien
- Haben Sie einen Blick auf diese: stackoverflow.com/a/2624377/1254743 Es ist nicht einmal mehr feinkörnigen, das können Sie leicht ändern, wenn nötig. Andyou brauchen nicht für den Aufbau Ihrer Strukturen doppelt (besonders schön, wenn Sie verschachtelte Strukturen).
- Ich denke, die Bibliothek PODCaster (zer7.com/software/podcaster und auf NuGet -) vielleicht hat genau an diesem problem, aber ich kann ehrlich nicht sagen, wie es verwendet werden soll, auch von den Proben.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier ist eine andere Lösung für das austauschen von endian.
Es ist einstellbar von Adam Robinsons Lösung hier: https://stackoverflow.com/a/2624377/1254743
Es ist sogar in der Lage, die Handhabung von geschachtelten Strukturen.
Wie angedeutet in meinem Kommentar auf @weismat Antwort, gibt es einen einfachen Weg, das zu erreichen big-endian-Strukturierung. Es beinhaltet eine Doppel-Umkehrung: die original-bytes vertauscht sind vollständig, dann die struct selbst ist die Umkehr der ursprünglichen (big-endian) data format.
Den
fooLe
undfooBe
imMain
haben die gleichen Werte für alle Felder. (Normalerweise ist die little-endian-Struktur und bytes würde nicht vorhanden sein, natürlich, aber dies zeigt deutlich die Beziehung zwischen den byte-orders.)HINWEIS: Siehe aktualisierten code einschließlich, wie man die bytes wieder aus dem struct.
Scheint es, muss es eine elegantere Lösung, aber dies sollte Sie wenigstens Los:
__makeref
(in der UInt16-Teil)?Endlich fand ich einen Weg, die waren nicht mit Reflexion und ist vor allem benutzerfreundlich. Es verwendet Mono ist DataConverter Klasse ( Quelle ), der leider ziemlich buggy an dieser Stelle. (Zum Beispiel, floats und doubles nicht richtig zu funktionieren scheint, string-parsing ist gebrochen, etc.)
Der trick ist, zu Entpacken und neu packen die bytes als big-endian, die einen string als Parameter benötigt, die beschreiben, welche Arten sind in dem byte-array (siehe Letzte Methode).Auch die byte-Ausrichtung ist schwierig: es gibt vier bytes im struct statt, weil das Marshalling scheint darauf angewiesen, dass 4-byte-Ausrichtung (ich habe noch nicht ganz verstanden, dass ein Teil). (EDIT: ich habe festgestellt, dass die Zugabe
Pack=1
zu denStructLayout
- Attribut der Regel kümmert sich um die byte-Ausrichtung Fragen.)Hinweis: dieser Beispielcode verwendet wurde, in LINQPad - Dump-Erweiterung-Methode druckt nur Informationen über das Objekt und gibt die Objekt (es ist fließend).
Stimme ich mit @weismat und glauben, es gibt keine Lösung.
Was Sie zeigen in Ihrem Beispiel ist, dass Sie Zugriff auf ein raw-byte-Puffer, als ob es eine ANDERE Struktur, ohne etwas zu ändern, und nicht das kopieren oder verschieben von Daten um, nichts. Einfach anpinnen, es zu vermeiden, es zu bewegen, weil der GC.
Dies ist im Grunde, was Sie erreichen in der Regel in C durch die Verwendung eines union-Typs, die beide Ihr Ziel-Struktur und ein byte-array der gleichen Größe.
Die gute Seite ist, dass es sehr effizient ist.
Dass hat mehrere Nachteile, der größte ist, dass Sie bekommen nur auf diese Weise Zugang zu Daten, die in der nativen Maschine, um (sei es LE oder BE). Damit Ihre ByteArrayToStructure ist nicht wirklich LE, es ist nur so, weil der Prozessor drunter ist LE. Wenn Sie, kompilieren Sie das gleiche Programm auf einem anderen Ziel, die geschehen WERDEN, es funktioniert in die andere Richtung und glauben, dass dein byte-array SEIN.
Andere Nachteile sind, dass müssen Sie sehr vorsichtig sein mit Daten Ausrichtung, bewusst sein, möglich Auffüllen, etc. und natürlich, dass es keine Möglichkeit gibt, ändern Sie die byte-Reihenfolge von LE zu WERDEN, ohne verschieben von Daten in Byte-array (wenn du ein 16-bit-Ganzzahlen nur die Arrays wie in deinem Beispiel ist dies nur etwa alle zwei bytes).
Ich hatte zufällig ein ähnliches problem und poundered nicht für diese Lösung, weil die bisherigen Nachteile und entschied sich zu verstecken meine input-Strukturen hinter Zugriffsmethoden verbergen Zugriff auf das Byte-array unter. Es ist vielleicht nicht so elegant, aber es ist einfach und vermeiden Sie auch das kopieren der Puffer oder verschieben von Daten in keiner Weise.
Haben Sie versucht, MiscUtil? Er hat eine utility-Klasse namens
EndianBitConverter
Konvertierung zwischen big-und little-endian-byte-arrays.{0, 1}
in eineushort
von1
, nicht für die gesamte Strukturen.Aus meiner Sicht brauchen Sie nur ein Array hinzuzufügen.Reverse() vor der Umwandlung des byte-Arrays.
Die traditionelle Lösung ist die Verwendung ntohl() und ntohs().
Den oben funktioniert auf jeder Plattform, die BSD-Sockets, egal ob in der big-endian, little-endian, oder etwas ganz komisch, wie eine VAX. Der umgekehrte Betrieb wird durchgeführt unter Verwendung von hton*().
Auf big-endian-Plattformen, die Funktionen sind in der Regel keine-ops und sollte daher null-Kosten.