mikrocontroller.net

Forum: Compiler & IDEs Bitfeld, union und Makro


Autor: Christian Obkircher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich speichere in meinem Programm das Datum auf folgende Weise:
typedef union {
  uint32_t dt_int;
  struct {
    uint32_t sec:    6;
    uint32_t min:    6;
    uint32_t hr:    5;
    uint32_t day:    5;
    uint32_t month:    4;
    uint32_t year:    6;
  } dt_struct;
} date_time_t;
Wenn ich nun aber bestimmte Zeiten speichern oder vergleichen möchte
(sind zur Compilezeit bekannt), dann muss ich entweder einzeln auf die
Variablen zugreifen, oder ich rechne es vorher in ein uint32_t um.
Ginge das nicht auch über ein Makro?
MfG Christian

Autor: Karsten Brandt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß nicht genau in welche Richtung deine Frage nun genau zielen
soll, aber ich habe hier mal ein paar Vorschläge:

typedef union 
{
  uint32_t dt_int;
  
  struct 
  {
    uint32_t sec    :6;
    uint32_t min    :6;
    uint32_t hr     :5;
    uint32_t day    :5;
    uint32_t month  :4;
    uint32_t year   :6;
  
  }; /* hier kein Name notwendig !? */
  
} date_time_t;



/* erster Vorschlag
 *******************/

date_time_t convTime( uint32_t year, 
                      uint32_t month, 
                      uint32_t day, 
                      uint32_t hr, 
                      uint32_t min,
                      uint32_t sec )
{
  date_time_t myTime;
  
  myTime.year  = year;
  mytime.month = month;
  myTime.day   = day;
  myTime.hr    = hr;
  myTime.min   = min;
  myTime.sec   = sec;
  
  return myTime;
}



/* zweiter Vorschlag 
 * (nur für die initialierte Deklaration einer date_time_t-Variable
sinnvoll)

****************************************************************************/

#define DATE_TIME( name, year, month, day, hr, min, sec ) \
                                                          \
  date_time_t name;                                       \
                                                          \
  name.year  = year;                                      \
  name.month = month;                                     \
  name.day   = day;                                       \
  name.hr    = hr;                                        \
  name.min   = min;                                       \
  name.sec   = sec;                                      
  
  /* Anwendung:
   * ----------
   * DATE_TIME( firstTime, 99, 12, 24, 11, 36, 45 );
   * DATE_TIME( secondTime, 87, 11, 23, 23, 45, 00 );
   *
   * if( firstTime.dt_int == secondTime.dt_int )
   * {
   *   // he, sie haben die gleiche Zeit ;-)
   *   ...
   * }
   **************************************************/


Ich hoffe das hilft vielleicht weiter.

Autor: Christian Obkircher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ kein Name notwendig: bist du sicher?
Eine union sind doch mehrere Variablen (mit je einem eigenen Namen),
die sich den selben Speicherplatz teilen. Eine davon ist hier eine
struct, aber deshalb muss sie doch trotzdem einen Namen haben, oder?

Zu deinen Vorschlägen: genau das wollte ich eigentlich verhindern.
Vielleicht hab ich das falsch rübergebracht: Es geht nicht (nur) darum,
mir die Tipparbeit zu sparen, sondern das Verwenden mehrerer
Zuweisungen, wo eigentlich eine einzige reichen würde. Es geht eher um
die Zeit, die dann bei der Ausführung gespart wird.
Hmmm, da fällt mir ein, es werden sowieso 4 Byte beansprucht, auf die
ja nacheinander zugegriffen werden muss, oder? Kommt das dann aufs
gleiche raus? Sprich, dauert ein Zugriff auf z.B. uint16_t gleich lange
wie zwei Zugriffe auf uint8_t? Und trifft das dann auch auf meinen
Datentyp zu, wo die Elemente "schief" in der struct liegen, also
nicht genau 8 Byte beanspruchen?

Autor: Karsten Brandt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Christian,

ob eine struct innerhalb einer union einen Namen habe muss, ist von
Compiler zu Compiler unterschiedlich.

Ich kann mich täuschen, aber soweit ich das im Moment überblicke ist
der Zugriff auf dt_int wesentlich schneller als über die Bitfelder.
Das kommt daher, da jedem Bitfeld ein uint32_t zugeordnet ist.
Somit greifst Du über 6 x 32bit zu, wenn Du alle Elemente einzeln
ansprichst.
Aber wie gesagt, genau weiss ich das auch nicht. Ist denke ich mal
ebenfalls abhängig vom Compiler.

Autor: Karsten Brandt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Evtl. wäre es besser die Bitfelder zu vergessen.
Speicherst Du die Variablen in einer normalen struct, kannst Du Sie
auch in einem Rutsch via meset() o.ä. setzen.
Nicht das dies nicht auch mit den Bitfeldern möglich wäre, jedoch ist
die eigentliche Wertzuweisung dann wesentlich komplizierter.
Gleiches gilt für die Datenauswertung.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn es dir genügt, dass das auf GCC compiliert, kannst du von
einer Extension Gebrauch machen.
int
isfoo(date_time_t d)
{
        if (d.dt_int == ((date_time_t){
                                .dt_struct.sec = 0,
                                .dt_struct.min = 0,
                                .dt_struct.hr = 23,
                                .dt_struct.day = 31,
                                .dt_struct.month = 1,
                                .dt_struct.year = 6
                }).dt_int)
                return 1;

        return 0;
}

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde einfach ne struct aus 6 Byte-Variablen nehmen.

Bitfelder werden deshalb sehr selten verwendet, weil sie in der Regel
sehr ineffizient sind.

Um einzelne Bits abzuspalten bzw. wieder zusammen zu setzen, wird ne
Menge Code und CPU-Zeit benötigt, was die 2 zusätzlichen Bytes SRAM
kaum Wert sein dürfte.


Peter

Autor: Karsten Brandt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Reden!

Autor: Christian Obkircher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, es geht weniger um die 2 Byte SRAM, sondern darum, dass diese
Zeiten samt ein paar erfassten Daten abgespeichert werden sollen.

Zitat Karsten Brandt:
Ich kann mich täuschen, aber soweit ich das im Moment überblicke ist
der Zugriff auf dt_int wesentlich schneller als über die Bitfelder.

Zitat Peter Dannegger
Um einzelne Bits abzuspalten bzw. wieder zusammen zu setzen, wird ne
Menge Code und CPU-Zeit benötigt, was die 2 zusätzlichen Bytes SRAM
kaum Wert sein dürfte.

Genau deshalb wollte ich es mit einem Makro machen. So dass intern
immer uint32_t verwendet wird, ich aber der Übersichtlichkeit halber
(und in einzelnen Fällen wo ich z.B. nur die Minute brauche) die
Variablen getrennt setzen kann.

@ Jörg: Ja, eigentlich brauch ich es nur auf dem GCC zu compilieren.
Was macht diese Extension genau? Gibts da irgendwo eine Doku dazu?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Genau deshalb wollte ich es mit einem Makro machen.

Ob du das nun in einem Makro oder ohne machst, ist egal. Das ändert am
Aufwand doch nichts.

> Was macht diese Extension genau? Gibts da irgendwo eine Doku dazu?

Ich würd mal schätzen, im Handbuch von GCC.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich würd mal schätzen, im Handbuch von GCC.

Daraus hatte ich sie hier.  Nennt sich "Compound literals",
und ist letztlich genau das, was du willst: die Benennung
einer Konstanten, die im Text angegeben ist (literal) für
ein "compound", also für struct/union/array.  Der C-Standard
kennt sowas nur für die Initialisierung, GCC kann sie als
Erweiterung für einen beliebigen konstanten Wert einsetzen.

Den Rest hatte ich dann einfach probiert, ob er das so
compilieren will.  Ausprobieren überlasse ich dir :), die
Syntax sollte von meinem Beispiel ja klar sein.  Hmm, das
heißt, die C99-Syntax für die Initialisierung bestimmter
Elemente eines "compounds" solltest du zuvor wohl bereits
verstanden haben.

Aus dem, was ich da auf der rechten Seite als Vergleichswert
stehen habe, kannst du natürlich auch allemal einen Makro
schreiben.  So viel Zeit hatte ich heute früh nur nicht, ich
hab' das schnell während einer anderen Veranstaltung
zusammengetippert.

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.