Forum: Compiler & IDEs offsetof Makro mit Zeiger auf Element in Struct


von Fragender (Gast)


Lesenswert?

Hallo zusammen,
ich programmiere nicht mit dem gcc sondern mit MPLab und dem Hi-Tech 
Pic16 C-Compiler. Aber ich denke und hoffe, dass ihr mir weiterhelfen 
könnt. Ich habe ein Struct wie folgt definiert:

   struct DATA{
      short value1;
      short value2;
      short value3;
      short value4;
   } Werte;

nun kann ich ja über das Makro offsetof die Position eines Elements im 
Struct herausfinden. Dies funktioniert auch mit folgendem Quelltext:

   offsetof(struct DATA, value2);

Nun stellen die Werte value1, value2,... unterschiedliche Werte dar, 
welche in einem Menü verändert werden können. Dazu gibt es einen Zeiger 
auf den zum aktuell ausgewählten Menüpunkt zugehörigen Wert. Also der 
Wert welcher im ausgewählten Menüpunkt geändert werden kann wird über 
einen Zeiger angesprochen bspw.:

   short *pointer = &Werte.value2;

in der Menüfunktion wird jetzt der Wert des Pointers verändert. Nun 
möchte ich die Position im Struct des Wertes herausfinden, auf welchen 
der Pointer zeigt. Dazu habe ich folgendes ausprobiert nur leider 
funktioniert das nicht:

   offsetof(struct DATA, *pointer);

Der Compiler bringt mir die Fehlermeldung "Zeiger erforderlich"

Kann mir hier bitte jemand weiterhelfen??? Habe ich einen Denkfehler 
oder geht das einfach nicht? Gibt es einen anderen Weg???

Vielen Dank schon im Vorraus!!!
Flo

von Andreas B. (Gast)


Lesenswert?

Das scheint eher eine Aufgabe für ein Array statt ein struct zu sein.

Fragender schrieb:
>     offsetof(struct DATA, *pointer);
>
> Der Compiler bringt mir die Fehlermeldung "Zeiger erforderlich"

Das zweite Argument für das Makro muss der Name eines Elements sein. So 
geht das nicht.

Um nur die Differenz zweier Zeiger zu erhalten, muss man sie voneinander 
abziehen (so weit, so offensichtlich).  Allerdings erhält man die 
Differenz in Einheiten der Datenobjekte, auf die gezeigt wird. Wenn die 
Differenz in Bytes gewünscht wird, muss man beide Zeiger nach char* 
casten.


Mit Arrays ist alles viel einfacher:
1
short Werte[4];
2
3
short *pointer = &Werte[1];
4
5
int index = pointer - Werte;

von Fragender (Gast)


Lesenswert?

Vielen Dank!

Habe aber leider nicht gesagt, dass im Struct nicht nur shorts, sondern 
auch andere Datentypen sind. Deshalb doch leider Struct. Mit einem Array 
habe ich es zuvor implementiert und das hat auch funktioniert. Dann 
müsste es doch aber folgendermaßen funktionieren:

    unsigned char *offset = (unsigned char)pointer - &(unsigned 
char)Werte

Flo

von Karl H. (kbuchegg)


Lesenswert?

Die Frage ist immer noch: WOZU?

Etwas derartiges hab ich in 30 Jahren noch nie benötigt.
(Mit scheint nämlich, du zäumst das Pferd von der falschen Seite auf)

von Andreas B. (Gast)


Lesenswert?

Fragender schrieb:
> Habe aber leider nicht gesagt, dass im Struct nicht nur shorts, sondern
> auch andere Datentypen sind. Deshalb doch leider Struct. Mit einem Array
> habe ich es zuvor implementiert und das hat auch funktioniert.

Man kann ein Array auch als Element von einem struct definieren…

Fragender schrieb:
> Dann
> müsste es doch aber folgendermaßen funktionieren:
>
>     unsigned char *offset = (unsigned char)pointer - &(unsigned
> char)Werte

Das funktioniert überhaupt nicht.

Und ich habe in meinem Beispiel die Variable nicht offset, sondern index 
benannt — aus dem Grund, dass es den Index ins Array ergibt und nicht 
den Byte-Offset. Wenn du den willst, musst du den Index einfach mit der 
Elementgröße, hier "sizeof (short)", multiplizieren.

von Chris (Gast)


Lesenswert?

Verwende ein Pointer als pointer, und nicht deren Inhalt !!!.
Dein falscher Code:
   offsetof(struct DATA, *pointer);

sollte lauten
   offsetof(struct DATA,  pointer);


Wenn du überlegst warum, wirst du warscheinlich auch erraten wieso.

von Chris (Gast)


Lesenswert?

Es stimmt, daß eine solches coding merkwürdig ist und im allgemeinen
vermieden wird, zumindest für das Beispiel das du uns erbracht hast.

von Andreas B. (Gast)


Lesenswert?

Chris schrieb:
> Verwende ein Pointer als pointer, und nicht deren Inhalt !!!.
> Dein falscher Code:
>    offsetof(struct DATA, *pointer);
>
> sollte lauten
>    offsetof(struct DATA,  pointer);

Das funktioniert genauso wenig, pointer ist kein Name eines Elements von 
struct DATA.

von Chris (Gast)


Lesenswert?

Stimmt, sorry.
Wenn pointer ein member von Werte ist, kannst du ptrdiff anstelle von 
offsetoff verwenden, sofern definiert. Ansonsten einfach
#define ptrdiff(x,y) (((unsigned int)&x)-(unsigned int)&y)

Ansonsten, geht nicht.

von Fragender (Gast)


Lesenswert?

Dass das ganze merkwürdig ausschaut und weshalb man soetwas eigentlich 
nicht verwenden sollte lasse ich mir gerne auch erklären, verstehe zwar 
nicht warum aber naja. In meinem Fall macht es aber Sinn, da es weniger 
Speicherplatz benötigt (habs getestet) und auch einfacher erweiterbar 
ist!!!

Habe das Problem übrigens folgendermaßen gelöst und es funktioniert:

unsigned char offset = (unsigned char*)pointer - (unsigned char*)&Werte

Vielen Dank an alle!!!
Flo

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.