Forum: Mikrocontroller und Digitale Elektronik globale Variable auf struct mappen


von Sebastian (Gast)


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

von Karl heinz B. (kbucheg)


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;

von Sebastian (Gast)


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

von Karl heinz B. (kbucheg)


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.

von Sebastian (Gast)


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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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

von Karl heinz B. (kbucheg)


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.

von Sebastian (Gast)


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

von Rolf Magnus (Gast)


Lesenswert?

Wie bist du denn auf die Idee gekommen, den Zeiger in einen char zu
konvertieren? Dadurch wird er zerstückelt.

von Karl heinz B. (kbucheg)


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!

von Sebastian (Gast)


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.

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.