Forum: Compiler & IDEs Bitfeld, union und Makro


von Christian Obkircher (Gast)


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

von Karsten Brandt (Gast)


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.

von Christian Obkircher (Gast)


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?

von Karsten Brandt (Gast)


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.

von Karsten Brandt (Gast)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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
}

von Peter D. (peda)


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

von Karsten Brandt (Gast)


Lesenswert?

Mein Reden!

von Christian Obkircher (Gast)


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?

von Rolf Magnus (Gast)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

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.