Forum: Compiler & IDEs Struktur in Struktur


von Andreas (Gast)


Lesenswert?

Hallo,


ich habe ein Problem bei dem ich mir nicht sicher bin ob ich es so 
machen kann. Hoffe ich kann es verständlich rüberbringen.

Ich will eine Struktur (z. B. gpsdata) in einer Struktur 
(velocity_message) anlegen. Dies funktioniert auch soweit. Jetzt will 
ich auf die in der Struktur befindlichen zweiten struct byteweise in 
einer Funktion sequentiell zugreifen und senden. Bei den bisherigen 
Versuchen war dies einwandfrei. Kann ich immer davon ausgehen, dass der 
Compiler die einzelnen Variablen in der zweiten Struktur hintereinander 
im RAM anlegt oder könnte es auch sein, dass die Variablen "kreuz und 
quer" verteilt werden?
1
typedef struct{
2
  uint32_t PGN;
3
  uint8_t priority;
4
  uint8_t destination;
5
  uint8_t payload_size;
6
  uint8_t *data;
7
} tMessageContainer;
8
9
struct{
10
  uint8_t senddata[2];
11
  char active_void;
12
  uint32_t time;
13
  int64_t lat;
14
  int64_t lon;
15
} gpsdata;
16
17
tMessageContainer velocity_message = {
18
  0x1F805,  
19
  6,      // priority
20
  0,      // destination
21
  sizeof(gpsdata),
22
  (uint8_t*) &gpsdata  // data
23
};


Danke für die Infos

von Studentle (Gast)


Lesenswert?

such mal nach verketten listen ;)

von Karl H. (kbuchegg)


Lesenswert?

Andreas schrieb:

> Ich will eine Struktur (z. B. gpsdata) in einer Struktur
> (velocity_message) anlegen.

Dann musst du das aber auch tun.

> Dies funktioniert auch soweit.

Im Moment machst du aber etwas anderes. In der ersten Struktur hast du 
eine Verpointerung auf die 2-te. Die 2-te ist damit NICHT Teil der 
ersten Struktur. Es ist wie in einem Buch
In dem einen Fall gibt es im Buch ein Kapitel, in dem Text steht.
Im anderen Fall (deinem Fall), steht im Buch nur: Der weiterführende 
Text findet sich in diesem und jenem anderen Buch.


> Versuchen war dies einwandfrei. Kann ich immer davon ausgehen, dass der
> Compiler die einzelnen Variablen in der zweiten Struktur hintereinander
> im RAM anlegt oder könnte es auch sein, dass die Variablen "kreuz und
> quer" verteilt werden?

Nein, die Member einer Struktur können vom Compiler nicht umsortiert 
werden. Die Reihenfolge ist durch deine Reihenfolge definiert. Aber der 
Compiler darf zwischen die Member (und auch nach dem letzten) unbenutzte 
Bytes einschieben um damit zb Alignment Restriktionen der 
zugrundeliegenden Hardware zu erfüllen.

von Tröte (Gast)


Lesenswert?

Also erstmal über Pointer und Strukturen schlaumachen.
Dann nach dem C-Attribut packed schauen.

__attribute__((_packed_))

von Andreas (Gast)


Lesenswert?

Erstmal Danke für die superschnelle Antwort.

Karl Heinz Buchegger schrieb:
> Dann musst du das aber auch tun.

Du hast recht. Hatte ich falsch ausgedrückt. In der einen soll nur ein 
Zeiger auf die zweite Struktur stehen.

Karl Heinz Buchegger schrieb:
> Alignment Restriktionen der
> zugrundeliegenden Hardware zu erfüllen

Was meinst Du hiermit? Ich bin kein Informatiker und kenne mich daher 
nicht aus.

von Tröte (Gast)


Lesenswert?

Wenn der Speicher 4-Byte-Aligned ist, und du eine 3-Byte-Variable 
innerhalb deiner Struktur einbaust, wird der Compiler ein Byte einfügen.
Daher -> mit der packed-Direktive bleiben alle Struktur-Offsets 
erhalten.

von Sam P. (Gast)


Lesenswert?

Aber auch _packed_ garantiert nicht, dass es keine Füllbytes gibt.

Es gibt nunmal Architekturen, da kann man nicht wahllos im Speicher 
Werte laden. Die frühen ARM-Architekturen (bis ARMv5 glaube ich) konnten 
32-Bit-Werte nur von Adressen laden, die Teilbar durch 4 waren. Hatte 
man dann kein Betriebssystem, das illegale Zugriffe abgefangen und durch 
eine Reihe von 8-Bit-Zugriffen (nebst Zusammensetzen des 32-Bit-Wertes) 
ersetzt hat, dann gab es eben einen Programmabbruch. Modernere ARM-Cores 
können sowas inzwischen, aber es laufen ja noch genug µCs mit ARM7 (was 
ein ARMv4 ist).

Was du vor hast, hat noch ein zweites potentielles Problem, nämlich die 
Byte Order. Wenn das empfangende System die Bytes in einem int anders 
anordnet, kriegst du für deine Integer Müll heraus. x86 und die meisten 
ARM sind little-endian (ich glaub AVR auch, oder?), MIPS (z.B. PIC32) 
ist big-endian. Es gibt lange quasi-religiöse Diskussionen, was nun 
besser ist, aber entscheidend ist, dass es diesen Unterschied gibt.

Da es bisher ging, tu dir keinen Zwang an und mach es wie bisher. Sobald 
du aber andere Hardware verwendest, musst dir bewusst sein, dass es 
passieren kann, dass es nicht mehr so funktioniert wie zuvor.

von Karl H. (kbuchegg)


Lesenswert?

Andreas schrieb:

> Was meinst Du hiermit? Ich bin kein Informatiker und kenne mich daher
> nicht aus.

Es gibt zb Prozessoren, bei denen ein Speicherzugriff IMMER an einer 
geraden Adresse im Speicher erfolgen MUSS!

machst du daher ein
1
struct test
2
{
3
  unsigned char val1;
4
  unsigned char val2;
5
};

dann wird ein vernünftiger Compiler zwischen val1 und val2 ein 
unbenutzes Byte einschieben, damit val2 wieder auf einer geraden 
Speicheradresse zu liegen kommt, wenn die komplette Struktur auf einer 
geraden Speicheradresse liegt. Genauso wird er nach dem val2 noch ein 
unbenutztes Dummy-Byte einschieben, damit die Strukturgröße wieder auf 
ein Vielfaches von 2 kommt, damit auch in einem Array gewährleistet ist, 
dass
* jeder einzelne Array Element auf einer geraden Adresse liegt
* jeder Struktur-Member jedes Array Elements auf einer
  geraden Adresse liegt

Will man das nicht, dann muss der Compiler Mehraufwand leisten, indem er 
zb bei einem Zugriff auf val2, das komplette Pärchen val1 und val2 als 
16 Bit Wert von der geraden Adresse (auf der val1 liegt) einliest und 
dann alles was nicht zu val2 gehört wegmaskiert. D.h. prinzipiell ist 
der Zugriff möglich, aber er ist mit mehr Aufwand verbunden als wenn 
sowohl val1 als auch val2 auf einer jeweils geraden Adresse liegen und 
damit notgedrungener Weise ein unbenutztes Byte zwischen den beiden 
Membern liegt.

von Andreas (Gast)


Lesenswert?

Danke Euch allen für die Antworten. Ihr habt mir damit weitergeholfen.


Grüße
Andreas

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.