Forum: Compiler & IDEs Offset eines Struktur-Elements bestimmen ohne vorhandene Variable
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 ---*/
|
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
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.
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 ---*/
|
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 ....
Moin,
Ich wuerde mal vermuten, dass du dann auch die offsetoffs schachteln
musst und dann deren Ergebnisse addieren.
Gruss
WK
Dergute W. schrieb:
> Ich wuerde mal vermuten, dass du dann auch die offsetoffs schachteln
> musst
Ich befürchte so etwas in der Richtung.
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 ---*/
|
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 ---*/
|
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 ...
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.
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.
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
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.
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
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.
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.
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.
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).
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.
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.
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.
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.
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.
|