structs in char*

Gast #6892245
Lesenswert?

Hey hallo,

Ich benötige auf meinem Controller eine struktur. Diese strutkur wird in 
der MAIN Ständig abgepollt und es geben eben Ereignisse die getriggert 
werden, sobald sich an der Struktur was ändert. Über I2C soll aber 
zugriff auf diese Struktur möglich sein. Ich hatte jetzt gedacht ich 
caste die struct einfach mal zu einem char* aber irgendwie scheint im 
speicher einige anders zu sein. Wie serialisiert man eine strukt 
möglichst einfach?
1
typedef struct {
2
  u16 dies;
3
  u16 UndDas;
4
  struct{
5
    u8 set_blub:1;
6
    u8 test_blub:1;
7
    u8 rel_an:1;
8
    u8 rel_an2:1;
9
    u8 reserved:4;
10
  }bits;
11
  u8 blubb;
12
  u16 vol2;
13
  u16 vol1;
14
  u16 version;
15
  u8 RESERVED1[50];
16
  u8 RESERVED2[50];
17
  u8 RESERVED3[50];
18
  u8 RESERVED4[50];
19
}REGISTER;
#6892279
Lesenswert?

attiny417 schrieb:
> zunächste Probiere ich mit microchip studio. Später (in serien
> Produktion) wolte ich avr-gcc + avr dude nehmen.

Aha...

Aber wenn du schon das Studio benutzt, schau halt mal in der Simulation 
in den Speicher, was da so steht..

Der avr-gcc 11, den ich hier habe, legt das alles so an, wie das da 
steht. Das Studio verwendet eine ältere Version. Vielleicht fehlt dem da 
ein packed, auch wenn das auf einem AVR eigentlich nicht beötigt werden 
sollte.

Oliver
Gast #6892286
Lesenswert?

attiny417 schrieb:
> Ich hatte jetzt gedacht ich
> caste die struct einfach mal zu einem char* aber irgendwie scheint im
> speicher einige anders zu sein.

Was passiert denn? Mit welchem Code?

Deine Struktur hat ja mindestens 224 Byte (wenn ich richtig gezählt 
hab), je nach Allignment auch an die 256. Soll das so?

Typische Probleme sind

 a) Allignment (REGISTER.Unddas fängt bei [4] an und nicht bei [2])
 b) Endianess (REGISTER.dies=3 schreibt 0,3 in den Speicher oder 3,0)
 c) Bitfelder sind ein eigenes Fass
 d) Dein Debugger ("im Speicher anders") ist wieder ein eigenes Fass
 e) Warnungen aus (und Schreibfehler, Verständnisfehler)
 f) ...
Gast #6892289
Lesenswert?

>> a) Allignment (REGISTER.Unddas fängt bei [4] an und nicht bei [2])
>> b) Endianess (REGISTER.dies=3 schreibt 0,3 in den Speicher oder 3,0)
>> c) Bitfelder sind ein eigenes Fass
>> d) Dein Debugger ("im Speicher anders") ist wieder ein eigenes Fass
>> e) Warnungen aus (und Schreibfehler, Verständnisfehler)
>> f) ...

I know :D

A) Im Beispiel oben wird man Problme mit dem Alignment bekommen, in 
meiner struct passe ich drauf auf das jede struct ein vielfaches von 4 
byte hat.
B) Endianess -> naja beide compiler die ich nutzen werde sind vom grunde 
auf gcc compiler, ich denke da springt das alignment nicht.
C) Siehe A / bzw Bitfelder nutze ich seit jahren.
d/e) -> feolgefehler durch fehlinterpretation :D
Gast #6892298
Lesenswert?

attiny417 schrieb:
> I know :D

Machst Du Witze? Du schreibst, Du hast ein Problem

> aber irgendwie scheint im speicher einige anders zu sein.

schreibst nicht dazu welches, sondern erklärst stattdessen, dass Du 
keine Fehler machst.

Dass der Compiler die Endianess bestimmt ist sicher nur ein Versehen. 
Und die genaue Größe der Struktur ist relativ egal, sizeof & co 
berücksichtigen das.
Gast #6892325
Lesenswert?

>>Dass der Compiler die Endianess bestimmt ist sicher nur ein Versehen.
Es ist leider nicht festgelegt, es kann es sein das ein anderer Compiler 
die Daten anders herum Speichert.


>>Und die genaue Größe der Struktur ist relativ egal, sizeof & co
>>berücksichtigen das.
Das stimmt nicht.

[code]
typedef struct {
    ui8 blub;
}test1;


typedef struct {
    ui8 blub;
    ui8 blub2;
}test2;
[/code}

soizeof(test2) wird 2 oder 4 ausgeben, genauso wie soizeof(test1). Es 
sei denn man "packt" mit #pragma push/pop

Daher ist es sehr sinnvoll darauf zu achten das man die size immer bei 
einem vielfachen von 4 hält, wenn man strukturen serialisieren möchte.
Gast #6892329
Lesenswert?

attiny417 schrieb:
> es kann es sein das ein anderer Compiler
> die Daten anders herum Speichert.

natürlich. Nur kommt der Compiler in Teufels-Küche, wenn er sich da 
nicht am µC und seinen Fähigkeiten orientiert. Und z.B. bei Deinem 
Nick-uC hätte ich jetzt nicht erwartet, dass er da flexibel ist.

attiny417 schrieb:
> Daher ist es sehr sinnvoll darauf zu achten das man die size immer bei
> einem vielfachen von 4 hält, wenn man strukturen serialisieren möchte.

Kann man so sehen. Man kann es auch anders rum sehen, dass nämlich der 
Compiler schon dafür sorgt, dass nichts schief geht. Er "macht" Deine 
Strukturen so groß, dass es passt. Probleme gibt es nur, wenn Du 
irgendwelche Dinge selbst ausrechnest (ohne sizeof oder []), vor allem 
wenn es um Arrays von Strukturen geht.

Aber wenn bei Dir doch alles funktioniert, dann OK, freut mich!
#6892343
Lesenswert?

Für Telegramm, die seriell übertragen werden, dürfen keine Lücken in der 
Struktur vorhanden sein.

Abhilfe:
1
struct my_struct {
2
   char a;
3
   int b;
4
} __attribute__ ((packed));

Bei unterschiedlichen Prozessorfamilien kann die Reihenfolge von Low und 
High vertauscht sein. Diese müssen dann im Empfänger gedreht werden.

char* speichert in der Struktur nur einen Zeiger vom Typ char !
#6892389
Lesenswert?

attiny417 schrieb:
> B) Endianess -> naja beide compiler die ich nutzen werde sind vom grunde
> auf gcc compiler, ich denke da springt das alignment nicht.

Das hat mehr mit der Zielplattform als mit dem Compiler zu tun. Daher 
kommt es stark darauf an, wer über I²C zugreifen will:

attiny417 schrieb:
> Über I2C soll aber zugriff auf diese Struktur möglich sein.

Wenn das auch ein AVR mit gcc ist, brauchst du dir keine Sorgen machen. 
Ansonsten musst du da genauer aufpassen.

Gerald K. schrieb:
> Für Telegramm, die seriell übertragen werden, dürfen keine Lücken in der
> Struktur vorhanden sein.

Die dürfen schon vorhanden sein. Sie müssen nur beidseitig gleich sein 
(und zwar unabhängig davon, wie sie übertragen werden). Das kann man 
z.B. auch erreichen, indem man zum Alignment Dummy-Elemente einfügt. Und 
man sollte ausschließlich die uint*_t-Datentypen oder vergleichbare mit 
genau definierter Breite nutzen.

> Abhilfe:
> struct my_struct {
>    char a;
>    int b;
> } _attribute_ ((packed));

Das kann fehlschlagen, wenn der Prozessor bestimmte Alignments zwingend 
voraussetzt. Und int kann auch auf Sender- und Empfänger-Seite 
unterschiedlich groß sein.

> Bei unterschiedlichen Prozessorfamilien kann die Reihenfolge von Low und
> High vertauscht sein. Diese müssen dann im Empfänger gedreht werden.

Oder im Sender. Man muss sich halt auf eine gemeinsame Byteoder einigen 
oder diese beim Start aushandeln.
Gast #6892414
Lesenswert?

Rolf M. schrieb:
> Gerald K. schrieb:
>> Für Telegramm, die seriell übertragen werden, dürfen keine Lücken in der
>> Struktur vorhanden sein.
>
> Die dürfen schon vorhanden sein. Sie müssen nur beidseitig gleich sein
> (und zwar unabhängig davon, wie sie übertragen werden).

Genau.

Ein Problem ergibt sich vielleicht, wenn man solche Strukturen 
vergleicht, z.B. mit memcmp.
Gast #6892420
Lesenswert?

A. S. schrieb:
> Rolf M. schrieb:
>> Gerald K. schrieb:
>>> Für Telegramm, die seriell übertragen werden, dürfen keine Lücken in der
>>> Struktur vorhanden sein.
>>
>> Die dürfen schon vorhanden sein. Sie müssen nur beidseitig gleich sein
>> (und zwar unabhängig davon, wie sie übertragen werden).
>
> Genau.
>
> Ein Problem ergibt sich vielleicht, wenn man solche Strukturen
> vergleicht, z.B. mit memcmp.

Das hat aber nichts mit der Übertragung zu tun.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren