globale Variable auf struct mappen

Gast #352542
Lesenswert?
• ▲
▼
Hallo,

ich habe aus einer Library eine globale Variable cDevStatus (unsigned
char). Ich mmöchte nun gerne auf diese über eine Bit Struktur
zugreifen.

Meine Idee ist recht simple, leider bekomme ich sie nicht zum Laufen.

struct sDevStatus
{
  unsigned char Stat0 :1;
  unsigned char Stat1 :1;
  .
  .
  unsigned char Stat7 :1;
};

union uDevStatus
{
  struct sDevStatus sDevStatus;
  unsigned char *pDevStatus;
};

union uDevStatus uDevStatus;

uDevStatus.pDevStatus = & cDevStatus;

Jetzt müßte ich doch über meine Structur direkt auf die globale
Variable cDevStatus schreiben, z.B:

uDevStatus.sDevStatus.Stat0 = 1;

Leider sehe ich beim Debuggen nicht das die 1 dann auch in cDevStatus
steht.

Kann mir vielleicht jemand meinen Denkfehler aufdecken.
Vielen Dank,
Sebastian
#352543
Lesenswert?
• ▲
▼
> union uDevStatus
> {
>   struct sDevStatus sDevStatus;
>   unsigned char *pDevStatus;
> };

Hier überlagerst du deine Bitstruktur mit einem Pointer.
D.h. deine Bitstruktur spiegelt (zum Teil) die Bits des
Pointers wieder und nicht der Variablen, auf die der Pointer
zeigt.

Dein Problem ist gar nicht so einfach zu lösen. So rum
müsste es aber gehen.
Du installierst dir einen Pointer auf so eine BitStruktur:

  struct sDevStatus* pDevStatus;

und jetzt sorgst du dafür, dass der Pointer auf das eine
Byte zeigt, dass dich interessiert:

   pDevStatus = ( struct sDevStatus* ) & cDevStatus;

Jetzt kannst du über pDevStatus auf das Byte zugreifen.
   pDevStatus->Stat0 = 1;

Der Trick liegt ganz einfach im Umcasten des Datentyps. Man
könnte daher den Pointer auch komplett einsparen, indem
man schreibt:

   ((struct sDevStatus)cDevStatus).Stat0 = 1;

Da das ein bischen länglich ist, würde ich mir erst mal
dafür ein Makro bauen:

#define DEV_STATUS ((struct sDevStatus)cDevStatus)

damit kann man das dann etwas schöner formulieren:

   DEV_STATUS.Stat0 = 1;
Gast #352544
Lesenswert?
• ▲
▼
Super,

erscheint mir absolut logisch. Werde ich nachher gleich mal
ausprobieren.

--Hier überlagerst du deine Bitstruktur mit einem Pointer.
--D.h. deine Bitstruktur spiegelt (zum Teil) die Bits des
--Pointers wieder und nicht der Variablen, auf die der Pointer
--zeigt.

Naja, also eigentlich dachte ich, das ich den pointer auf den Anfang
der Bitstruktur zeigen lasse. Also nicht überlagern. Bzw. den Pointer
so ausrichte das er auf die Adresse der globalen Variable zeigt. Somit
müßte doch die Bitstruktur genau über der globalen Variablen liegen.
Oder?

Sebastian
#352545
Lesenswert?
• ▲
▼
Das möchtest du vielleicht machen.
Aber das hier

> union uDevStatus
> {
>   struct sDevStatus sDevStatus;
>   unsigned char *pDevStatus;
> };

macht ganz was anderes. Eine union benutzt für
alle seine Member den gleichen Speicher.
Damit liegen sDevStatus und pDevStatus an der
selben Speicheradresse. Wohin der Pointer zeigt
ist den sDevStatus völlig Wurscht. sDevStatus
spiegelt den Inhalt des Pointers wieder, nicht
worauf der Pointer zeigt.
Gast #352546
Lesenswert?
• ▲
▼
Ok ich hab's kapiert.

Die Variante mit dem pointer funktioniert ausgezeichnet :-).

Die Variante mit dem Typcast, allerdings nicht.

((struct sDevStatus)cDevStatus).Stat0 = 1;

// Fehler "Type Cast": char kann nicht in struct sDevStatus
konvertiert werden.
// Fehler Der linke Teil muss eine Klasse/Struktur/Union sein.

Wäre tool wenn diese Variant auch noch funktionieren würde.

Vielen, vielen Dank,
Sebastian
#352548
Lesenswert?
• ▲
▼
> (*((struct sDevStatus *) (void) &cDevStatus)).Stat0 = 1;

:-)

  (*((struct sDevStatus *) (void *) &cDevStatus)).Stat0 = 1;

                                 ^
                                 |

Keine Angst, sieht nur kompliziert aus. Der Compiler sollte
das eigentlich ordentlich wegoptimieren.


> ((struct sDevStatus)cDevStatus).Stat0 = 1;
> // Fehler "Type Cast": char kann nicht in struct sDevStatus
>   konvertiert werden.
> // Fehler Der linke Teil muss eine Klasse/Struktur/Union sein.

Sorry. Habs vorher nicht ausprobiert. Ich hätte allerdings
schwören können, dass ein C-Compiler das anstandslos akzeptiert.
Mein C ist allerdings nach 10 Jahren C++ etwas rostig und ich
bin nicht mehr auf der Höhe der Zeit was Veränderungen im
C-Standard angeht.
Gast #352549
Lesenswert?
• ▲
▼
(*((struct sDevStatus *) (char) &cDevStatus)).Stat0 = 1;

Das obige Konstrukt kann zwar kompiliert werden allerding erhalte ich
immer Access violations. Den obigen Typcast muss ich mir mal am WE in
Ruhe anschauen. Mit der Pointer-Variante bin ich momentan absolut
glücklich :-).

Sebastian
#352551
Lesenswert?
• ▲
▼
> (*((struct sDevStatus *) (char) &cDevStatus)).Stat0 = 1;
>
> Das obige Konstrukt kann zwar kompiliert werden allerding erhalte
> ich immer Access violations.

Das wundert mich nicht.
Zerlegen wir mal:

 cDevStatus                 Variable cDevStatus

 &cDevStatus                davon die Adresse (16 Bit)

 (char)&cDevStatus          das ganze gecastet nach char.
                            Da haben wir aber ein Problem:
                            Eine Adresse hat 16 Bit, ein char
                            nur 8 Bit. Also muss irgendwas verloren
                            gehen!

  (...)                     Der Rest ist nur noch Makulatur.
                            Dadurch, dass die Adresse von 16 Bit
                            auf 8 Bit gekürzt wurde, ist alles
                            andere sinnlos.

Casts sind Waffen!
Gast #352552
Lesenswert?
• ▲
▼
Mist ich hatte das Sternchen bei void vergessen. Dann habe ich einfach
mal schnell ein char eingefügt und schon "kam der Compiler" durch.
Mit bekannten runtime folgen.

Mit (void *) funktioniert das alles perfekt.

Also was lernt man draus. Erst kapieren dann probieren ;-).

An alle,
Merci.

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