Forum: Compiler & IDEs Offset eines Struktur-Elements bestimmen ohne vorhandene Variable


von Wastl (hartundweichware)


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 ---*/

von Oliver S. (oliverso)


Lesenswert?

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

Oliver

von Wastl (hartundweichware)


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.

von Wastl (hartundweichware)


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 ---*/

von Wastl (hartundweichware)


Lesenswert?

Wastl schrieb:
> Ich denke ich hab es gerade selbst gefunden.

Funktioniert leider nicht bei ineinandergeschachtelten
Structs. Es sei denn ich habe noch nicht herausgefunden wie
man das formuliert ....

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Ich wuerde mal vermuten, dass du dann auch die offsetoffs schachteln 
musst und dann deren Ergebnisse addieren.

Gruss
WK

von Wastl (hartundweichware)


Lesenswert?

Dergute W. schrieb:
> Ich wuerde mal vermuten, dass du dann auch die offsetoffs schachteln
> musst

Ich befürchte so etwas in der Richtung.

von Daniel A. (daniel-a)


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 ---*/

von Wastl (hartundweichware)


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 ---*/

von Apollo M. (Firma: @home) (majortom)


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 ...

von Wastl (hartundweichware)


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.

von Apollo M. (Firma: @home) (majortom)


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.

: Bearbeitet durch User
von Max H. (nilsp)


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

von Bruno V. (bruno_v)


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.

von Oliver S. (oliverso)


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

von Johann L. (gjlayde) Benutzerseite


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
Wenn die Struktur für's RAM zu groß ist, warum dann alles mögliche reinstopfen? Man kann doch
13
14
[c]
15
#include <avr/eeprom.h>
16
17
typeA_t varA EEMEM;
18
typeB_t varB EEMEM;
19
typeC_t varC EEMEM;
20
...

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.

von Le X. (lex_91)


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.

von Le X. (lex_91)


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.

von Johann L. (gjlayde) Benutzerseite


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).

: Bearbeitet durch User
von Bruno V. (bruno_v)


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.

von Hannes J. (Firma: _⌨_) (pnuebergang)


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.

: Bearbeitet durch User
von Rolf M. (rmagnus)


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.

von Le X. (lex_91)


Lesenswert?

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

Und wie kommt man dann darauf, zwei typedefs zu verwenden?
Kein Vorteil, aber doppelter Pflegeaufwand und fehleranfällig.

von Bruno V. (bruno_v)


Lesenswert?

Hannes J. schrieb:
> copy_from_eeprom_to_ram(&ram_destination, &(eeprom_source->common),
> sizeof(common_data));

und mit offsetof hätte die Zeile als zweiten Parameter offsetof (statt 
&), dass den meist notwendigen Cast nach size_t schon enthält.

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.