Forum: PC-Programmierung C# Leidiges Thema Struct to byte array / byte array to Struct


von otti (Gast)


Lesenswert?

Hallo Forengemeinde,
Ich bin ein Anfänger in der C# Welt!
Ich habe hier im Forum die Suche  und auch Google bemüht eine Lösung für 
mein Problem zu kriegen, leider mit bescheidenem Erfolg.
Zu meinem Problem, ich möchte für eine Serielle Kommunikation zwischen 
Mikrocontroller und Pc eine Struktur verwenden. Auf der Mikrocontroller 
Seite ("C")kann ich einfach mittels Zeiger die Struktur byteweise 
versenden und auch wieder empfangen. Auf der Pc Seite ("C#") gestaltet 
sich das für einen Anfänger schwieriger! Ich habe mehrere Ansätze 
versucht folgende Struktur
1
public struct Protocol
2
        {
3
            public byte adress;
4
            public byte command;
5
            public byte len;
6
            public Int16[] recivebuffer;
7
            public uint Rtimeout;
8
            public Int16 rec_CRC;
9
        };
in ein byte Array zu  konvertieren.
hier der erste Ansatz:
1
public byte[] ByteArrayFromStruct(object obj)
2
        {
3
            int length = Marshal.SizeOf(obj);
4
            byte[] array = new byte[length];
5
6
            IntPtr ptr = Marshal.AllocHGlobal(length);
7
            Marshal.StructureToPtr(obj, ptr, true);
8
            Marshal.Copy(ptr, array, 0, length);
9
            Marshal.FreeHGlobal(ptr);
10
11
            return array;
12
        }
13
byte[] test = Serial.ByteArrayFromStruct(Proto);
aber sobald in der Struktur ein Array vorkommt funktioniert das Ganze 
nicht mehr
der zweite Ansatz
1
public Byte[] TestSerialization(object obj)
2
        {
3
            BinaryFormatter formatter = new BinaryFormatter();
4
            MemoryStream stream = new MemoryStream();
5
            formatter.Serialize(stream, obj);
6
            Byte[] buffer = stream.ToArray();
7
            return buffer;
8
        }
9
byte[] test = Serial.TestSerialization(Proto);
bei diesem Ansatz wird das Array 188 byte lang
Was mach ich Falsch?
Wäre sehr dankbar für Eure Professionelle  Hilfe

Gruß
otti

von JojoS (Gast)


Lesenswert?

man kann die Struktur auch mit dem BinaryWriter / Reader Elementweise 
zusammenbauen oder lesen.
Wenn man die Strukturen verwenden will muss man auf das Alignement 
achten, damit legt der Compiler die Variablen auf für den Prozessor 
'gerade' Adressen. Das sieht in C# aber nicht schöner aus als das 
Elementweise schreiben.
1
    private const int maxSpare = 16;
2
3
    [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)] 
4
      public struct teleData
5
    {
6
      [MarshalAs(UnmanagedType.ByValArray, SizeConst=8)] public byte[] sampleString;
7
8
      public float aFloat;
9
      public byte aByte;
10
11
      [MarshalAs(UnmanagedType.ByValArray, SizeConst=maxSpare)] public float[] spare;
12
    };
13
14
    private teleData tele;
15
    private byte[] bArray = null;
16
17
    unsafe protected override void DoSomething()
18
    {
19
      if( bArray == null )
20
      {
21
        tele = new teleData();
22
23
        //  Header
24
        int n = Marshal.SizeOf(tele);
25
        bArray = new byte[n];
26
27
        tele.spare = new float[maxSpare];
28
      }
29
30
31
      //  In Byte Array übertragen
32
      fixed( byte* pArray = bArray )
33
        Marshal.StructureToPtr(tele, new IntPtr(pArray), false);
34
35
    }

von otti (Gast)


Lesenswert?

Entschuldigt mich Bitte aber ich kann mit dem Oben genannten Beispiel 
nichts anfangen.

Wäre nett wenn es mir jemand erklären könnte!

Danke Gruß

Otti

von JojoS (Gast)


Lesenswert?

in die Strukutrdeklaration müssen die Attribute
 [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)]
rein damit beim Marshalling die Daten richtig aneinandergepackt werden. 
In meiner Struktur sind einige Typen als Beispiel drin, komplizierter 
sind Arrays in Strukturen weil die ja intern nicht als einfache 
Bytearrays abgelegt werden. Und das mit dem fixed Pointer war auch 
nötig, weiss grad nicht warum.
Aber wie gesagt, einfacher ist eigentlich die BinaryWriter Klasse zu 
verwenden. Du brauchst einen MemoryStream und kannst dann mit 
bw.Write(einByte) in den Stream schreiben.

von otti (Gast)


Lesenswert?

JojoS schrieb:
> komplizierter
> sind Arrays in Strukturen weil die ja intern nicht als einfache
> Bytearrays abgelegt werden.

Genau das ist mein Problem.
Leider brauche ich genau das.
Kann man einen Stream auch in ein byte Array umleiten??

Danke für Deine Hilfe

Gruß
Otti

von JojoS (Gast)


Lesenswert?

um den Stream in ein ByteArray zu schreiben hast du ja schon die 
richtige Memberfunktion in deinem Beispiel drin:
Byte[] buffer = stream.ToArray();

Um den Stream zu füllen gibts nur die WriteByte() Methode, das ist für 
andere Datentypen als Bytes natürlich umständlich, deshalb braucht man 
noch den BinaryWriter als Helfer um beliebige andere Daten in den Stream 
zu schreiben.

von otti (Gast)


Lesenswert?

JojoS schrieb:
> Um den Stream zu füllen gibts nur die WriteByte() Methode, das ist für
> andere Datentypen als Bytes natürlich umständlich, deshalb braucht man
> noch den BinaryWriter als Helfer um beliebige andere Daten in den Stream
> zu schreiben.

kannst du mir bitte ein kleines Beispiel machen.

Möchte mich für Deine Hilfe schon mal herzlich bedanken!

Gruß

otti

von JojoS (Gast)


Lesenswert?

so könnte es aussehen:
1
        {
2
            MemoryStream ms = new MemoryStream(512);
3
            BinaryWriter bw = new BinaryWriter(ms);
4
5
            bw.Write((byte)0x11);   // address
6
            bw.Write((byte)0x22);   // command
7
            bw.Write((byte)40);     // length
8
            for(Int16 i=0; i<16; i++)
9
            {
10
                bw.Write(i);        // receivebuffer
11
            }
12
            bw.Write((uint)1000);   // Rtimeout
13
            bw.Write((Int16)1234);  // crc
14
15
            Byte [] ba = ms.ToArray();      // convert to Array
16
17
            SerialPort com = new SerialPort("COM1", 19200);     // open serial port
18
            com.Open();
19
            com.Write(ba, 0, ba.Length);                        // send data
20
            com.Close();
21
        }

von otti (Gast)


Lesenswert?

Vielen herzlichen Dank für Dein Beispiel!

Ich muß mich erst mal durcharbeiten durch den Code (Anfänger)

Gruß
Otti

von Johnny B. (johnnyb)


Lesenswert?

Ein "Zauberwort" das Dir vielleicht noch hilft ist "Serialisieren".
Suche mal im Internet nach diesbezüglichen Beispielen, es gibt einige 
davon.

von Sas K. (saku)


Lesenswert?

Hi Community,

sorry, dass ich den alten Thread nochmal auskrame.
Wurde zum geposteten Problem mittlerweile eine Lösung gefunden?

Ich hab ein ähnliches Problem. Ich schicke über eine Tcp Verbindung 
double und Bytes und empfange diese in einem Array - Buffer.
Nun möchte ich aber auf die einzelnen Einträge des Arrays zugreifen um 
diese wieder in einen double oder byte - Wert dekodieren zu können.

Das müsste ich dann auch über einen Struct machen, oder?

Viele Grüße

von Peter II (Gast)


Lesenswert?

Sas K. schrieb:
> Das müsste ich dann auch über einen Struct machen, oder?

nein, das sollte man nicht mit einer struct machen.

Empfange doch ersmal die byte du die brauchst und wandelst sie dann in 
deinen Datentype um.

Bei double z.b

BitConverter.ToDouble(byte[] value,int startIndex)
BitConverter.GetBytes(Double)


http://msdn.microsoft.com/de-de/library/system.bitconverter.aspx

von saku (Gast)


Lesenswert?

Hi, gut das hat mittlerweile schonmal geklappt.
Jetzt stehe ich vor dem nächsten Schritt, Daten von meinem C# Progamm 
über eine Tcp-Verbindung zu senden. Mache es derzeit über die Socket 
klasse mit socket.Send.

Problem dabei ist, dass ich nicht nur byte sondern auch double versenden 
will und diese vor dem Versenden ja zunächst umwandeln muss.
Hab es schon damit probiert:
System.Convert.ToByte(49.678) (also in diesem Beispiel soll die 
Doublezahl 49.678 versendet werden).

Auf meiner Empfangsseite kommen aber immer nur "50" an. Also ganze byte 
- Werte.


Wie könnte ich das denn eleganter lösen? Evtl erst eine Struct aufbauen 
und diese dann komplett in ein Bytearray wandeln?

von Peter II (Gast)


Lesenswert?

saku schrieb:
> Wie könnte ich das denn eleganter lösen?

einfach mal den vorherigen Post lesen?

BitConverter.GetBytes(Double)

von saku (Gast)


Lesenswert?

Sorry, das hatte ich irgendwie überlesen.

Leider gibt er mir da den Fehler aus, das "Eine implizite Konvertierung 
vom Typ "byte[]" in "byte" " nicht möglich ist.
1
  byte[] senden = new byte[c];
2
                        sbyte s1 = -126;
3
                        byte b1 = (byte)s1;
4
                        byte b2 = 120;
5
                        double d3 = 17.234;
6
7
8
                        senden[0] = b1;
9
                        senden[1] = b2;
10
                        senden[2] = BitConverter.GetBytes(d3);
11
                        
12
                  
13
14
                        socket.Send(senden);

von saku (Gast)


Lesenswert?

Es funktioniert zwar gut, wenn ich mir einfach noch ein weiteres Array 
definiere und den Double dann über GetBytes in dieses Array schreibe. 
Aber das müsste sich doch auch noch anders lösen lassen, oder?
1
                     int c = 2;
2
                        int c1 = 8;
3
                        byte[] senden = new byte[c];
4
                        byte[] senden1 = new byte[c1];
5
                        sbyte s1 = -126;
6
                        byte b1 = (byte)s1;
7
                        byte b2 = 120;
8
                        double d3 = 17.234;
9
10
                        senden[0] = b1;
11
                        senden[1] = b2;
12
                        senden1 = BitConverter.GetBytes(d3);
13
                 
14
                        socket.Send(senden);
15
                        socket.Send(senden1);

Nochmals vielen Dank für eure zahlreichen und hilfreichen Antworten!

von Arc N. (arc)


Lesenswert?

saku schrieb:
> Es funktioniert zwar gut, wenn ich mir einfach noch ein weiteres Array
> definiere und den Double dann über GetBytes in dieses Array schreibe.

GetBytes schreibt nichts in das Array senden1, sondern liefert ein neues 
Array zurück, das dann über senden1 "erreichbar" ist (siehe die GetBytes 
Typsignatur).

> Aber das müsste sich doch auch noch anders lösen lassen, oder?

s.o. Beitrag von JojoS mit MemoryStream + BinaryWriter

von Sas K. (saku)


Lesenswert?

> GetBytes schreibt nichts in das Array senden1, sondern liefert ein neues
> Array zurück, das dann über senden1 "erreichbar" ist (siehe die GetBytes
> Typsignatur).
>

genau, so meinte ich das ja ;) hatte mich vielleicht ein wenig 
undeutlich ausgedrückt.

>
> s.o. Beitrag von JojoS mit MemoryStream + BinaryWriter

Ok was in diesem Fall doch um einiges umständlicher wäre, als einfach 
mehrere Arrays zu senden.


Vielen Dank :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.