Forum: PC-Programmierung C# struct innerhalb einer struct


von Roblue (Gast)


Lesenswert?

Hallo!

Da ich momentan echt nicht weiter weiß und mit C# noch nicht viel 
gemacht habe, frage ich mal hier die Experten. Habe einen PIC der mir 
über die serielle Schnittstelle auf Anforderung aktuelle Daten wie 
Temperatur, Motorpositionen usw. schicken soll. Am PIC habe ich alle 
relevanten Werte in einer struct stehen, die sich wiederum aus einzelnen 
selbstdefinierten Typen besteht (also auch nur struct).
Sieht dann z.B. so aus:
1
typedef struct
2
{
3
  // Allgemein
4
  signed short Temperatur;
5
  struct StepperMotor MotorA;
6
} werte;

Auch wenn sich viele mit dem Stil nicht anfreunden können, arbeite ich 
schon einige Jahre auf diese Art :)
Mir geht es nun darum, die struct "werte" in meiner C#-Anwendung 
auszuwerten. Die Kommunikation funktioniert einwandfrei, nur bekomme ich 
es mit C# nicht in den Griff, eine Struktur wie oben innerhalb einer 
anderen zu erstellen. In C# habe ich die obrige struct so angelegt:
1
[StructLayout(LayoutKind.Sequential, Size = 56)]
2
    public struct werte
3
    {
4
        public SByte Temperatur;
5
        public StepperMotor MotorA;
6
    };
Nun Initialisiere ich in meinem C#-Programm die struct so
1
private werte aktWerte = new werte();
und möchte dann eben z.B. per aktWerte.MotorA.steps den Wert in einer 
Textbox anzeigen lassen.

Meine Daten kommen in Telegrammform und nicht in Klartext. Ich schicke 
die struct werte wirklich byte für byte an den PC. Nun habe ich diesen 
Code im Netz gefunden, der für eine struct funktioniert. Allerdings 
nicht, wenn ich eine struct innerhalb einer struct habe -> wie eben 
aktWerte.MotorA ist.
1
/// <summary>
2
        /// Kopiert Daten aus einem Byte-Array in eine entsprechende Strukture (struct). Die Struktur muss ein sequenzeilles Layout besitzen. ( [StructLayout(LayoutKind.Sequential)] 
3
        /// </summary>
4
        /// <param name="array">Das Byte-Array das die daten enthält</param>
5
        /// <param name="offset">Offset ab dem die Daten in die Struktur kopiert werden sollen.</param>
6
        /// <param name="structType">System.Type der Struktur</param>
7
        /// <returns></returns>
8
        static object ByteArrayToStruct(byte[] array, int offset, Type structType)
9
        {
10
            if (structType.StructLayoutAttribute.Value != LayoutKind.Sequential)
11
                throw new ArgumentException("structType ist keine Struktur oder nicht Sequentiell.");
12
13
            //int size = Marshal.SizeOf(structType);
14
            int size = structType.StructLayoutAttribute.Size;
15
            if (array.Length < (offset + size))
16
                throw new ArgumentException("Byte-Array hat die falsche Länge.");
17
18
            byte[] tmp = new byte[size];
19
            Array.Copy(array, offset, tmp, 0, size);
20
21
            GCHandle structHandle = GCHandle.Alloc(tmp, GCHandleType.Pinned);
22
            object structure = Marshal.PtrToStructure(structHandle.AddrOfPinnedObject(), structType);
23
            structHandle.Free();
24
25
            return structure;
26
        }

So übergebe ich meinen Empfangsbuffer (Byte-Array) an die Funktion
1
aktWerte = (werte)ByteArrayToStruct(rx_data, 4+2, typeof(aktWerte));

Die Temperatur, also das Byte gleich am Anfang der struct, funktioniert 
einwandfrei. Innerhalb von aktWerte.MotorA stehen dann die Werte vom PIC 
irgendwo in der struct.
Vielleicht weiß ja jemand von Euch Rat.

Liebe Grüße,
Roblue

von Arc N. (arc)


Lesenswert?

LayoutKind.Explicit versucht und dann z.B.
1
struct xyz {
2
[FieldOffset(0)] a b;
3
[FieldOffset(1)] c d;
4
...
5
}

von Rocky B. (bitrocker)


Lesenswert?

Roblue schrieb:
> aktWerte = (werte)ByteArrayToStruct(rx_data, 4+2, typeof(aktWerte));
"aktWerte" ist kein Typ, kann also demzufolge nicht mit dem 
typeof-Operator aufgerufen werden.
1
aktWerte = (werte)ByteArrayToStruct(rx_data, 4 + 2, typeof(werte));

Roblue schrieb:
> [StructLayout(LayoutKind.Sequential, Size = 56)]
> public struct werte
> {
>    public SByte Temperatur;
>    public StepperMotor MotorA;
> };

Wie hast du "StepperMotor" deklariert?

von Roblue (Gast)


Lesenswert?

Danke, den Fehler mit dem Typ hab ich beim schreiben des Codes im 
Posting gemacht. In der Software ist das natürlich der Typ "werte".
Inzwischen bin ich etwas schlauer geworden, bzw. funktioniert die 
Übergabe der Werte nun korrekt.
1
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]

Das Pack = 1 macht den Unterschied. Nun steht alles dort, wo es hin 
gehört. Durch einen anderen Thread bin ich drauf gekommen, was das Pack 
eigentlich macht. Mit dieser Angabe muss ich nun auch nicht mehr das 
"size" Attribut manuell festlegen. Die Größe stimmt nun auch mit 
Marshal.SizeOf.

Vielen Dank für Eure Hilfe!

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.