mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik globale Variable auf struct mappen


Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
(*((struct sDevStatus *) (void) &cDevStatus)).Stat0 = 1;

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rolf Magnus (Gast)
Datum:

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

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.