Bitfeld, union und Makro

Gast #367696
Lesenswert?
• ▲
▼
Hallo,
ich speichere in meinem Programm das Datum auf folgende Weise:
1
typedef union {
2
  uint32_t dt_int;
3
  struct {
4
    uint32_t sec:    6;
5
    uint32_t min:    6;
6
    uint32_t hr:    5;
7
    uint32_t day:    5;
8
    uint32_t month:    4;
9
    uint32_t year:    6;
10
  } dt_struct;
11
} 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
Gast #367697
Lesenswert?
• ▲
▼
Ich weiß nicht genau in welche Richtung deine Frage nun genau zielen
soll, aber ich habe hier mal ein paar Vorschläge:
1
typedef union 
2
{
3
  uint32_t dt_int;
4
  
5
  struct 
6
  {
7
    uint32_t sec    :6;
8
    uint32_t min    :6;
9
    uint32_t hr     :5;
10
    uint32_t day    :5;
11
    uint32_t month  :4;
12
    uint32_t year   :6;
13
  
14
  }; /* hier kein Name notwendig !? */
15
  
16
} date_time_t;
17

18

19

20
/* erster Vorschlag
21
 *******************/
22

23
date_time_t convTime( uint32_t year, 
24
                      uint32_t month, 
25
                      uint32_t day, 
26
                      uint32_t hr, 
27
                      uint32_t min,
28
                      uint32_t sec )
29
{
30
  date_time_t myTime;
31
  
32
  myTime.year  = year;
33
  mytime.month = month;
34
  myTime.day   = day;
35
  myTime.hr    = hr;
36
  myTime.min   = min;
37
  myTime.sec   = sec;
38
  
39
  return myTime;
40
}
41

42

43

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

48
****************************************************************************/
49

50
#define DATE_TIME( name, year, month, day, hr, min, sec ) \
51
                                                          \
52
  date_time_t name;                                       \
53
                                                          \
54
  name.year  = year;                                      \
55
  name.month = month;                                     \
56
  name.day   = day;                                       \
57
  name.hr    = hr;                                        \
58
  name.min   = min;                                       \
59
  name.sec   = sec;                                      
60
  
61
  /* Anwendung:
62
   * ----------
63
   * DATE_TIME( firstTime, 99, 12, 24, 11, 36, 45 );
64
   * DATE_TIME( secondTime, 87, 11, 23, 23, 45, 00 );
65
   *
66
   * if( firstTime.dt_int == secondTime.dt_int )
67
   * {
68
   *   // he, sie haben die gleiche Zeit ;-)
69
   *   ...
70
   * }
71
   **************************************************/

Ich hoffe das hilft vielleicht weiter.
Gast #367698
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?
Gast #367699
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.
Gast #367700
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.
Moderator Persönliche Seite #367701
Lesenswert?
• ▲
▼
Wenn es dir genügt, dass das auf GCC compiliert, kannst du von
einer Extension Gebrauch machen.
1
int
2
isfoo(date_time_t d)
3
{
4
        if (d.dt_int == ((date_time_t){
5
                                .dt_struct.sec = 0,
6
                                .dt_struct.min = 0,
7
                                .dt_struct.hr = 23,
8
                                .dt_struct.day = 31,
9
                                .dt_struct.month = 1,
10
                                .dt_struct.year = 6
11
                }).dt_int)
12
                return 1;
13

14
        return 0;
15
}
#367702
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
Gast #367704
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?
Gast #367705
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.
Moderator Persönliche Seite #367706
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

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.