Little Endian, Big Endian oder generelles Umdrehen von Bytefolgen in C#

Little Endian, Big Endian oder generelles Umdrehen von Bytefolgen in C#

Ab und zu sehnt man sich auch unter C# zur guten alten C++ (naja, C) Zeit zurück, wo man noch beliebig tiefen Zugriff auf alles hatte, beliebig Typen casten konnte und – so lange man ein wenig aufgepasst hat – so wahre Wunder bewirken kann. (Ja, und das konnte nicht jeder.. und nach ein paar Anfangsfehlern ist auch alles gut gelaufen.)

Die Typensicherheit ist in C# etwas schwieriger zu umgehen, jedoch geht auch das, und damit lassen sich dann beispielsweise in hardwarenaher oder Netzwerk-Programmierung Werte dem Zielformat anpassen, z. B. auf Byteebene in der Reihenfolge umdrehen – und dass dann auch für floats et al.

Nachdem ich nach kurzem Googeln keine Lösung gefunden habe, die sich schön für mich übernehmen läßt (nur verschiedene, die jedoch direkt das Kopieren (und zumindest minimale Verstehen) unzähliger Funktionen erfordert hätten) stelle ich hier mal meine Lösung in die Google-Suche ein – und natürlich für all die fleißigen, regelmäßigen Leser hier (hallo, ihr rockt!).

rock rule

Beim Schreiben habe ich sogar eine schöne Lösung mit Generics gefunden. Und direkt ein halbwegs realistisches Beispiel gefunden.

Wer sich wundert: die Werte, die in der EEPROM Struktur stehen sind natürlich nicht mehr lesbar – hier hätte man beliebige Typen nehmen können. Allein passt es so für die Konvertierungsfunktion besser, ferner hat man so auf einen Blick eine Ahnung, welche Werte wo stehen sollen.

Da man typischerweise nachher auf die Struktur per byte* zugreift, habe ich die Funktion noch dazugestellt. Auch das Layout von 1 Byte ist hier meist nützlich – wer auf dieser Ebene arbeitet benötigt meist eher den Platz als daß er sich um ein CPU-freundliches Alignment kümmern würde. Alternativ wird die Struktur ohnehin von Extern vorgegeben und man hat als Softwerker keine Wahl. Auch ein Beispiel von Fülldaten habe ich direkt hinzugefügt – um das vorgegebene Alignment einzuhalten.

Getestet habe ich den Code übrigens nicht, sondern aus dem Gedächtnis aufgeschrieben.. jedenfalls compiliert er und ähnlichen (lauffähigen) Code habe ich neulich geschrieben.. sollte also direkt funktionieren. Mit 1, 2 Anpassungen bzgl. der tatsächlichen Daten evtl. 🙂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        // actually, many more places have issues with little-/big-endian conversion, like networking
        // this is actually rather easy as shown below - or course performance is not an issue here
        // though it should behave ok unless you want to use it of 100s of MBs
        unsafe public class EEPROM
        {
            // typically, eeproms are packed tight
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            struct payload
            {
                public uint serial;
                public float gain;
                public fixed byte name[10];
                fixed byte padding1[2];
                public float offset;
            }
 
            payload pl;
 
            EEPROM()
            {
                pl = new payload();
            }
 
            T reverse<T>(T a)
            {
                T[] b = new T[] { a };
                int size = Marshal.SizeOf(a);
                byte[] c = new byte[size];
                Buffer.BlockCopy(b, 0, c, 0, size);
                c = c.Reverse().ToArray();
                Buffer.BlockCopy(c, 0, b, 0, size);
                return b[0];
            }
 
            public uint Serial {
                get { return reverse(pl.serial); }
                set { pl.serial = reverse(value);}
            }
 
            public float Offset
            {
                get { return reverse(pl.offset); }
                set { pl.offset = reverse(value); }
            }
 
            public byte* ToByteArray()
            {
                fixed (payload* p = &pl)
                    return (byte*)p;
            }
        }

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.