Offset eines Struktur-Elements bestimmen ohne vorhandene Variable

#7533136
Lesenswert?

Problem: in einem kleinen RAM sollen stückweise EEPROM-Elemente gelesen/geschrieben werden. Die Struktur des EEPROMs ist grösser als das was im RAM gehalten werden kann. Somit ergibt sich das Problem den Offset eines Struktur-Elements zu bestimmen ohne eine komplette Instanz einer Struktur angelegt zu haben.

Soweit ich aus Suchanfragen entnommen habe funktioniert <offsetof> nur mit Bezug auf eine existierende Struktur - so werden die Beispiele formuliert. Ich würde aber gerne die Funktionalität von <offsetof> auf eine Struktur-Definition bezogen, also nicht auf eine existierende Struktur haben.

Wie geht das bitte? (hier im Code ohne Anwendung von <offsetof>)

1
void struct_test (void)
2
{
3
  uint32_t offsC;  // zu berechnender Offset
4

5
  typedef struct  // Struktur Definition
6
  {
7
    uint16_t  varA;
8
    uint32_t  varB;
9
    uint8_t   varC;
10
  } mystruct_def;
11

12
  mystruct_def  sample;  // eine Instanz der Struktur
13

14
  // so geht's z.B. mit angelegter Struktur-Variable
15
  offsC = (uint8_t*)&sample.varC - (uint8_t*)&sample.varA;
16

17
  //offsC = (uint8_t*)&mystruct_def.varC - (uint8_t*)&mystruct_def.varA;
18
  // geht nicht da <mystruct_def> keine Variable im Speicher ist
19

20
} /* --- struct_test ---*/
#7533143
Lesenswert?

Oliver S. schrieb:

Das C-Makro offsetof() benötigt den Typ, keine Instanz. Das reicht für den Compiler ja völlig aus, die offsets zu berechnen.

Dann schreibe doch bitte eine funktionierende Zeile hin die zu meinem Beispiel-Code passt.

Ich habe nur Beispiele gesehen in denen das Argument von <offsetof> eine existierende Struktur ist, keine Struktur-Definition.

#7533150
Lesenswert?

Ich denke ich hab es gerade selbst gefunden. Der Gedanke kommt beim Reden ....

1
void struct_test (void)
2
{
3
  uint32_t offsC;  // zu berechnender Offset
4

5
  typedef struct  // Struktur Definition
6
  {
7
    uint16_t  varA;
8
    uint32_t  varB;
9
    uint8_t   varC;
10
  } mystruct_def;
11

12
  offsC = offsetof(mystruct_def, varC);
13

14
} /* --- struct_test ---*/
#7533235
Lesenswert?

Wastl schrieb:

Wastl schrieb:

Ich denke ich hab es gerade selbst gefunden.

Funktioniert leider nicht bei ineinandergeschachtelten Structs.

Klar geht das.

1
void struct_test (void)
2
{
3
  uint32_t offsB;  // zu berechnender Offset
4
  typedef struct  // Struktur Definition
5
  {
6
    uint16_t  varA;
7
    struct {
8
      uint32_t  varB;
9
    } verschachtelt;
10
    uint8_t   varC;
11
  } mystruct_def;
12
  offsB = offsetof(mystruct_def, verschachtelt.varB);
13
} /* --- struct_test ---*/
#7533255
Lesenswert?

Daniel A. schrieb:

Klar geht das.

Stimmt, jetzt wo du es schreibst .... Danke für den Schubser ...

Hier ein Beispiel in meiner Ausführung mit separat definierter Struktur und Sub-Struktur.

1
uint32_t calc_offs (void)
2
{
3
  uint32_t offs_val;  // zu berechnender Offset
4

5
  typedef struct  // untergeordnete Struktur Definition
6
  {
7
    uint32_t  varA;
8
    uint16_t  varB;
9
    uint8_t   varC;
10
  } smallstruct_def;
11

12
  typedef struct  // uebergeordnete Struktur Definition
13
  {
14
    smallstruct_def  smallA;
15
    smallstruct_def  smallB;
16
    smallstruct_def  smallC;
17
  } top_struct_def;
18

19
  offs_val = offsetof(top_struct_def, smallB.varC);
20

21
  return offs_val;
22

23
} /* --- calc_offs ---*/
(Firma: @home) #7533401
Lesenswert?

Wastl schrieb:

Somit ergibt sich das Problem den Offset eines Struktur-Elements zu bestimmen

Warum der Offset gebraucht werden soll, erschließt sich nicht aus der Problembeschreibung. Wenn du mal das Pronlemm besser beschreibst , dann zeige ich, wie das OHNE den Offset geht. Hier wird nur rumgespielt mit struct anstatt mit Sinn verwendet.

... vom smallstruct_def anstatt smallstruct_t bekommt man Bauchschmerzen!

Also zeige Beispiele wie du den offsetof() Wert verwenden willst ...

#7533405
Lesenswert?

Apollo M. schrieb:

... vom smallstruct_def anstatt smallstruct_t bekommt man Bauchschmerzen!

Ok, ich tu dir was Gutes und verwende in Zukunft in der Öffentlichkeit und privat immer *_t Strukturdefinitionen anstat von *_def. Das kann ich nicht verantworten dass du im Anblick meiner Veröffentlichungen Bauchschmerzen bekommst.

Apollo M. schrieb:

Warum der Offset gebraucht werden soll, erschließt sich nicht aus der Problembeschreibung.

Im Übrigen hat keiner Derjenigen die sich zu Wort gemeldet haben eine Frage nach dem Sinn meines Tuns gestellt. Damit nehme ich an dass es bisher alle verstanden haben und auch einen Sinn darin erkannt haben.

Weitere Auführungen erspare ich mir, ich kann jetzt genau das machen was ich vorhabe.

(Firma: @home) #7533410
Lesenswert?

Wastl schrieb:

Im Übrigen hat keiner Derjenigen die sich zu Wort gemeldet haben eine Frage nach dem Sinn meines Tuns gestellt. Damit nehme ich an dass es bisher alle verstanden haben und auch einen Sinn darin erkannt haben.

Aua, das tut weh!

Wenn du glücklich bist, weil du denkst alles zu können, dann ist alles perfekt!

Sehr überzeugend zu denken, dass zwei pro und eine contra Wortmeldung eine sichere Selbstbestätigung sind.

#7533418
Lesenswert?

Wastl schrieb:

Ok, ich tu dir was Gutes und verwende in Zukunft in der Öffentlichkeit und privat immer *_t Strukturdefinitionen anstat von *_def.

Mep, nicht machen.

Alle _t Typen sind für Posix reserviert. Wenn Du selbst einen Typ mit _t anlegst riskierst Du bei jedem Standard Update einen Typenkonflikt.

Das betrifft noch ein paar andere Namen. GCC hat netterweise eine Liste: https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html

#7533501
Lesenswert?

Apollo M. schrieb:

Aua, das tut weh

Apollo, der TO hat ein typisches Problem, dass auch erfahrene Programmierer mit offsetof lösen und zur ersten Verwendung eine Frage, die schnell und sachlich beantwortet wurde

Jetzt kommst Du, mäkelst an seinen Bezeichnern und versprichst eine alternative Lösung, wenn er sich komplett auszieht.

Vermutlich wird Deine Lösung nur dann funktionieren, wenn er die Programmiersprache wechselt, die Architektur umschmeißt oder 2 Statements da nutz, wo vorher eines war.

Wenn Du eine anfängertaugliche alternative zu offsetof kennst, in plain C, für den Anwendungsfall hier (einzelne Elemente im eeprom spiegeln, dann sttelle das in deinem Thread vor oder ins Wiki.

#7533662
Lesenswert?

Wastl schrieb:

Im Übrigen hat keiner Derjenigen die sich zu Wort gemeldet haben eine Frage nach dem Sinn meines Tuns gestellt. Damit nehme ich an dass es bisher alle verstanden haben und auch einen Sinn darin erkannt haben.

Nein, aber den Kommentar, daß deine nur sehr rudimentären C-Kentnisse auch darauf schließen lassen, daß du da nach einer Lösung für ein klassisches xy-Problem suchst, hatte ich mir verkniffen. Aber bitte, wurde nachgeliefert.

Oliver

Persönliche Seite #7533965
Lesenswert?

Wastl schrieb:

Problem: in einem kleinen RAM sollen stückweise EEPROM-Elemente gelesen/geschrieben werden. Die Struktur des EEPROMs ist grösser als das was im RAM gehalten werden kann.

Ich muss gestehen, dass ich das Problem auch nicht wirklich verstehe,

1
> void struct_test (void)
2
> {
3
>   ...
4
> 
5
>   typedef struct  // Struktur Definition
6
>   {
7
>     uint16_t  varA;
8
>     uint32_t  varB;
9
>     uint8_t   varC;
10
>   } mystruct_def;
11

12

13
Wenn die Struktur für's RAM zu groß ist, warum dann alles mögliche reinstopfen? Man kann doch
14

15
[c]
16
#include <avr/eeprom.h>
17

18
typeA_t varA EEMEM;
19
typeB_t varB EEMEM;
20
typeC_t varC EEMEM;
21
...

und die dann einlesen?

Oder, wenn man gerne einen Struct darum hat, auf die Komponenten zugreifen so wie man's braucht?

1
#include <avr/eeprom.h>
2

3
typedef ... typeA_t;
4
typedef ... typeB_t;
5

6
typedef struct
7
{
8
    typeA_t varA;
9
    typeB_t varB;
10
} eeprom_t;
11

12
// Als extern in *.h
13
eeprom_t eeprom EEMEM;
14

15
typeA_t varA;
16
typeB_t varB;
17

18
int main (void)
19
{
20
    eeprom_read_block (&varA, &eeprom.varA, sizeof (varA));
21
    eeprom_read_block (&varB, &eeprom.varB, sizeof (typeB_t));
22
    return 0;
23
}

Beim Zugriff hat man die entsprechenden Objekte doch zur Hand.

#7534132
Lesenswert?

Johann L. schrieb:

Ich muss gestehen, dass ich das Problem auch nicht wirklich verstehe,

in deiner Lösung gehst du aber davon aus dass es sich a) um einen Atmel handelt und b) die Verwendung von eeprom.h gewünscht ist.

Ich muss gestehen, ich verstehe die Frage des TE und halte das Vorgehen für sinnvoll. Du kannst dir dein Eeprom-Layout einfach per typedef struct vom Compiler erzeugen lassen und dir mit offsetof die Adressen für die read- und write-Funktionen berechnen lassen. Dazu braucht es keine Instanz im RAM.

#7534138
Lesenswert?

Apollo M. schrieb:

Warum der Offset gebraucht werden soll, erschließt sich nicht aus der Problembeschreibung. Wenn du mal das Pronlemm besser beschreibst , dann zeige ich, wie das OHNE den Offset geht. Hier wird nur rumgespielt mit struct anstatt mit Sinn verwendet.

gähn

Der Nachste der meint, besser zu wissen was der TE braucht und was nicht.

Ich verstehe seine Frage, seinen Lösungsansatz und kann bezeugen dass dieser Ansatz durchaus auch im Professionellem eingesetzt wird. Folgere doch bitte von deinem Horizont nicht auf Andere.

Persönliche Seite #7534237
Lesenswert?

Le X. schrieb:

Johann L. schrieb:

Ich muss gestehen, dass ich das Problem auch nicht wirklich verstehe,

in deiner Lösung gehst du aber davon aus dass es sich a) um einen Atmel handelt und b) die Verwendung von eeprom.h gewünscht ist.

Das wird verwendet zum Lokatieren im EEprom und zum Zugriff; ist jetzt nicht sooo exotisch.

Du kannst dir dein Eeprom-Layout einfach per typedef struct vom Compiler erzeugen lassen und dir mit offsetof die Adressen für die read- und write-Funktionen berechnen lassen.

In meinem Beispiel (Teil2) wird das EEprom auch als Struct modelliert.

Um sich die Adresse z.B. einer Komponente des Structs zu besorgen gibt's doch den &-Operator in C/C++, und wieviel Bytes zu lesen sind erhält man mit sizeof.

Dazu braucht es keine Instanz im RAM.

In meinem Beispiel auch nicht. Das Beispiel zeigt nur die Verwendung. Um die Adressen und Größen der Komponenten zu erhalten genügt der Typedef für den Struct und (eine externe Referenz) auf das EEprom Object.

Und die Adresse des EEprom-Objects braucht mam mit sizeof ja auch. (und wenn man die Adresse als 0x0 hart codiert, brauch man auch im meinem Beispiel KEINE Referenz des Objects).

#7534252
Lesenswert?

Johann L. schrieb:

Um sich die Adresse z.B. einer Komponente des Structs zu besorgen gibt's doch den &-Operator in C/C++, und wieviel Bytes zu lesen sind erhält man mit sizeof.

Der TO ist ein Anfänger, der das Define für offsetof nicht kannte und auch nicht den Cast des Nullpointers zur Adressbestimmung.

Mit 100%iger Sicherheit ist sein Code nicht optimal. Ja und? Er hat jetzt einen Ansatz mit dem er arbeiten und Erfahrungen sammeln kann.

Wenn ich ein fremdes Auto erstmals fahre, möchte ich nicht noch, dass jemand zuschaut und Tips gibt.

Hier haben wir einen Fahranfänger mit 100 Experten (Mitleser) auf dem Beifahrersitz, die sehen wollen, ob er früh genug blinkt. Ohne dass ein Crash uns den Versicherungsrabatt kostet.

Lassen wir Compiler und HW zeigen, ob er richtig fährt. Er kann jederzeit fragen, wenn er dauernd crashed.

#7534286
Lesenswert?

Wenn man seine Sachen sauber definiert gibt es keinen Grund für offsetof(). Welches im Prinzip sowieso nur mit Pointern spielt. Je nach Compiler etwas grenzwertig mit einem Null-Pointer.

Wenn man voraus denkt:

Man legt die gemeinsamen Daten einfach an den Anfang, d.h. Offest 0.

1
// Data that happens to be stored in RAM or EEPROM
2
typedef struct {
3
    int com1;
4
    int com2;
5
} common_data;
6

7
// Data that happens to be stored in EEPROM
8
typedef struct {
9
    common_data common;
10
    int ep1;
11
    int ep2;
12
} eeprom_data;
13

14
common_data ram_destination;
15
// Ignore details of eeprom access mechanisms for demonstration purposes
16
eeprom_data *eeprom_source = <eeprom source address>;
17
copy_from_eeprom_to_ram(&ram_destination, eeprom_source, sizeof(common_data));

Man muss halt vorher nur mal für fünf Cent nachdenken wie man seine Datenstruktur ins EEPROM legen möchte.

Man kann das ganze auch noch komplizierter machen wenn man es symmetrischer haben möchte:

1
// Data that happens to be stored in RAM or EEPROM
2
typedef struct {
3
    int com1;
4
    int com2;
5
} common_data;
6

7
// Data stored in RAM
8
typedef struct {
9
    common_data common;
10
} ram_data;
11

12
// Data that happens to be stored in EEPROM
13
typedef struct {
14
    common_data common;
15
    int ep1;
16
    int ep2;
17
} eeprom_data;

Und wenn man es doch versaut hat:

1
// Data that happens to be stored in RAM or EEPROM
2
typedef struct {
3
    int com1;
4
    int com2;
5
} common_data;
6

7
// Data that happens to be stored in EEPROM
8
// screwed-up layout
9
typedef struct {
10
    int ep1;
11
    common_data common;
12
    int ep2;
13
} eeprom_data;
14

15
common_data ram_destination;
16
// Ignore details of eeprom access mechanisms for demonstration purposes
17
eeprom_data *eeprom_source = <eeprom source address>;
18

19
copy_from_eeprom_to_ram(&ram_destination, &(eeprom_source->common), sizeof(common_data));

Ach ja, alles unter der Annahme man hat das Allignment im Griff.

#7534414
Lesenswert?

Hannes J. schrieb:

Wenn man seine Sachen sauber definiert gibt es keinen Grund für offsetof(). Welches im Prinzip sowieso nur mit Pointern spielt. Je nach Compiler etwas grenzwertig mit einem Null-Pointer.

Nein, da ist nichts grenzwertig. offsetof() ist ein Standard-Makro. Wie der Compiler das umsetzt, ist seine Sache, aber es muss entsprechend der Spezifikation funktionieren.

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