Forum: Compiler & IDEs Einzelne Bytes in Struktur aufrufen


von Dennik (Gast)


Lesenswert?

Hallo,

in einer (beliebigen) Struktur möchte ich alle Bytes nacheinander 
aufrufen, um sie in einem EEPROM zu speichern. Mir ist es dabei 
vollkommen egal, wie die einzelnen Elemente angeordnet sind, ich möchte 
einfach nur das komplette Gebilde Byte für Byte im EEPROM speichern.

Wie kann ich in der Struktur die einzelnen Bytes (0...n, n ist bekannt) 
aufrufen?

Danke für alle Antworten, mit vielen Grüßen Dennik

von ... (Gast)


Lesenswert?

Z.B. indem Du die Struktur (genauer deren Addresse) auf uint8_t* 
castest.
Oder eine Union mit einem passenden Array drumrumbastelst.
Oder gleich die richtige Funktion zum schreiben in den EEPROM benutzt.

von klaus (Gast)


Lesenswert?

Dennik schrieb:
> Mir ist es dabei
> vollkommen egal, wie die einzelnen Elemente angeordnet sind, ich möchte
> einfach nur das komplette Gebilde Byte für Byte im EEPROM speichern.

Byte-weiser Zugriff wäre in etwa so möglich:
1
struct EGAL
2
{
3
  int x;
4
  int y;
5
};
6
// ...
7
8
struct EGAL s;
9
10
char* ptr = (char*)&s;
11
12
int i;
13
for (i = 0; i < sizeof(struct EGAL); ++i)
14
{
15
  // print each byte
16
  printf("%d,", ptr[i]);
17
}

von Frank B. (f-baer)


Lesenswert?

Wenn du die Struktur in einer union mit einer Variable passender Größe 
zusammenfasst, dann kannst du über die Einzelvariable die komplette 
Struktur auslesen. Nur das Rückschreiben ist etwas komplizierter, weil 
du dann wieder die Einzelgrößen schreiben musst.

Beispiel:
1
union DEINE_UNION{
2
  struct DEIN_STRUCT{
3
    u8 deine_variable1;
4
    u8 deine_variable2;
5
  };
6
  u16 deine_zusammenfassung;
7
};

von peterguy (Gast)


Lesenswert?

Wenn ich dein Problem richtig verstanden habe, dann heisst die Lösung 
deines Problems "union".

Da sieht dann so ungefähr aus:
1
union{
2
 byte[LEN_STRUCT] rawData;
3
 struct {
4
   // hier kommen deine Structfelder rein >
5
   int mySignal;
6
 } Data;
7
} myUnion;
Kannst dann über myUnion.rawData[x] auf die Rohdaten zugreifen, und über 
myUnion.Data.mySignal auf einzelne Nutzdaten.

Hoffe das in obigem Code kein Fehler drinnen ist, habe die Syntax nicht 
überprüft.

Oder halt auf einen byte pointer casten, aber das finde ich persöhnlich 
nicht so sauber.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Die Union-Variante setzt voraus, daß der byte-Array-Teil größer sein 
muss als der struct-Teil. Das aber ist nicht garantiert, und so ist das 
eine schöne potentielle Fehlerquelle.

Sofern das Ergebnis des byteweisen Zugriffs nicht auf einer komplett 
anderen Hardwarearchitektur wiederum in einer Struktur genutzt werden 
soll, ist am typecast nichts "unsauber".

von Karl H. (kbuchegg)


Lesenswert?

peterguy schrieb:

> Oder halt auf einen byte pointer casten, aber das finde ich persöhnlich
> nicht so sauber.


Egal wie du es machst, diese Operation wird niemals 'sauber' sein. Denn 
streng genommen ist auch die Union Variante nicht vom C-Standard 
gedeckt.
Genausogut könnte ich argumentieren, dass das umcasten des Pointers auf 
einen anderen Typ die etwas ehrlichere Variante ist, weil die Absicht 
dahinter klarer ist, als das verschleierte einschreiben in eine Union 
und auslesen über einen anderen Union-Member (und genau das ist dann 
auch der Punkt, an dem der Standard keine Zusicherung mehr macht: 
offiziell darf man eine Union nur über den Member auslesen über den die 
Daten auch in die Union gekommen sind)

Diese Lösung mit union
1
union{
2
 byte[LEN_STRUCT] rawData;
3
 struct {
4
   // hier kommen deine Structfelder rein >
5
   int mySignal;
6
 } Data;
7
} myUnion;
ist allerdings ganz schlecht, weil sie den Programmierer dazu zwingt die 
Strukturgröße zu kennen. Bei solchen Sachen IMMER eine Lösung suchen, 
die das Abzählen von irgendwelchen Größen dem Compiler aufbürdet. 
Sprich: sizeof benutzen!

von Frank B. (f-baer)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Die Union-Variante setzt voraus, daß der byte-Array-Teil größer sein
> muss als der struct-Teil. Das aber ist nicht garantiert, und so ist das
> eine schöne potentielle Fehlerquelle.

Mit __attribute__((_packed_)) stellt das kein Problem dar.

von Dennik (Gast)


Lesenswert?

Vielen Dank für die schnellen Antworten.
Den Vorschlag vom klaus habe ich implementiert. Zumindest ist der 
Compiler schon mal damit zufrieden. Wenn ich morgen auch noch die 
EEPROM-Leseroutine fertig habe, werde ich testen können, ob es 
funktioniert.

Mit vielen Grüßen und nochmals Danke, Dennik

von Frank B. (f-baer)


Lesenswert?

Das hier
>
1
> union{
2
>  byte[LEN_STRUCT] rawData;
3
>  struct {
4
>    // hier kommen deine Structfelder rein >
5
>    int mySignal;
6
>  } Data;
7
> } myUnion;
8
>

ist übrigens noch aus einem ganz anderen Grund schlecht. Die union kann 
so nur über rawData initialisiert werden, direkt in mySignal zu 
schreiben, funktioniert nicht.

von klaus (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Die Union-Variante setzt voraus, daß der byte-Array-Teil größer sein
> muss als der struct-Teil. Das aber ist nicht garantiert, und so ist das
> eine schöne potentielle Fehlerquelle.
1
struct DATA
2
{
3
  u8 x;
4
  u8 y;
5
};
6
7
#define LEN sizeof(struct DATA)
8
9
union DATA_ACCESS
10
{
11
  struct DATA data;
12
  u8 access[LEN];
13
};

Die union kann je nach Alignment Platz verschwenden, aber das "access" 
Array ist nie zu klein.

von Karl H. (kbuchegg)


Lesenswert?

Dennik schrieb:
> Vielen Dank für die schnellen Antworten.
> Den Vorschlag vom klaus habe ich implementiert. Zumindest ist der
> Compiler schon mal damit zufrieden. Wenn ich morgen auch noch die
> EEPROM-Leseroutine fertig habe, werde ich testen können, ob es
> funktioniert.

?
Du brauchst 24 stunden um die Aufrufe so zu schreiben
1
   eeprom_read_block( (uint8_t*)&myStructVariable,
2
                      (uint8_t*)&eemyStructVariable,
3
                      sizeof( *myStructVariable ) );

bzw.
1
   eeprom_write_block( (uint8_t*)&myStructVariable,
2
                       (uint8_t*)&eemyStructVariable,
3
                       sizeof( *myStructVariable ) );

für die Variablen
1
struct irgendwas {
2
  ...
3
};
4
5
struct irgendwas eemyStructVariable EEMEM;
6
struct irgendwas myStructVariable;

von Dennik (Gast)


Lesenswert?

> ?
> Du brauchst 24 stunden um die Aufrufe so zu schreiben

Nein - es wird in 24 Stunden fertig sein.

Die Daten werden übrigens dreifach im EEPROM abgelegt und sowohl nach 
dem schreiben, als auch beim Lesen miteinander verglichen. Weiterhin 
wird das interne Prozessabbild des verwendeten µCs zyklisch mit den 
gespeicherten EEPROM-Daten aktualisiert. - Incl. Test dauert das einfach 
etwas.

Mit freundlichen Grüßen, Dennik

von Dennik (Gast)


Lesenswert?

Die ersten Test's des Programms sind positiv verlaufen. Die von klaus 
vorgeschlagene Lösung scheint gut zu funktionieren.

Nochmals herzlichen Dank (an alle), Dennik

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.