Forum: Mikrocontroller und Digitale Elektronik C: Bit in einer Variable eigenen Namen geben?


von Tio T. (misterten)


Lesenswert?

Hallo,

ich sehe grad den Wald vor lauter Bäumen nicht:

ich habe einen zwei Strukturen, eine mit Byte-Variablen und eine mit 
Bit-Variablen:

struct
{   unsigned char fix;
    unsigend char foxy;
}
X;


struct
{   unsigned a:1;
    unsigned b:1;
    unsigned c:1;
}
Y;


Wie mache ich das nun, dass Y.a das erste Bit von X.fix, Y.b das zweite 
Bit von X.fix ist, usw.? Ich blick das grad nicht.

danke schonmal!
tio

von Werner B. (werner-b)


Lesenswert?

Die Strukturen in eine Union packen.

von Tio T. (misterten)


Lesenswert?

Ach, d.h. ich würde es so schreiben:


union fix
{   unsigned a:1;
    unsigned b:1;
    unsigned c:1;
};


?

von Daniel C. (cagara)


Lesenswert?

Naja einfacher wäre es doch einfach den Inhalt von

unsigned char fix;

per memcpy in das struct Y zu kopieren.

Mehr brauchst du nicht zu tun!

von Benutzer N. (benutzername)


Lesenswert?

versuch mal

1
union muh
2
{
3
  struct
4
  {   
5
    unsigned char fix;
6
  }X;
7
8
  struct
9
  {   
10
    unsigned b0:1;
11
    unsigned b1:1;
12
    unsigned b2:1;
13
    unsigned b3:1;
14
    unsigned b4:1;
15
    unsigned b5:1;
16
    unsigned b6:1;
17
    unsigned b7:1;
18
  }Y;
19
};
20
21
22
23
void main()
24
{
25
  muh test;
26
27
  test.X.fix = 193;
28
29
  printf("%d\n",test.X.fix);
30
  printf("%d %d %d %d %d %d %d %d \n",test.Y.b7, test.Y.b6, test.Y.b5, test.Y.b4, test.Y.b3, test.Y.b2, test.Y.b1, test.Y.b0);
31
}


und die Ausgabe auf der Konsole sieht wie folgt aus
1
193
2
1 1 0 0 0 0 0 1


Viel Spaß damit ;)

von Matthias D. (marvin42)


Lesenswert?

Da hilft ein Blick in den Urvater aller C-Anleitungen, 
Kerningham-Rithice bei Prentice-Hall.

Eine "union" hat den Zweck an nur einer Speicherstelle verschiedene 
Inhakte unterbringen zu können. Die folgende union

union u_1 {
  int ivalue;
  float fvalue;
  char* svalue;
} u;

kann entweder einen integer, einen float oder einen char* aufnehmen, der 
Compiler macht sich aber automatisch groß genug, damit auch die grösste 
Variable hineinpasst (vorsicht mit "int", das ist nicht bei jedem 
Prozessor gleich gross, dass kan 8,16 oder 32 bit sein).

Deine union "fix" ist demnach nur 1 Bit groß und kann enteder aus a, 
oder b, oder c bestehen. Wenn du aber zwei Bytes bitweise ansprechen 
willst, dann würde ich folgendes vorschlagen:

union myUnion
{
  struct
  {
    char fix;
    char foxi;
  } uByte;

  struct
  {
    unsigned a:1;
    unsigned b:1;
    // usw und so fort
  } uBit;
} uutype;

wenn du nun folgende Variable erzeugst:

uutype uvar;

dann sollte folgender Code möglich sein:

uvar.uByte.fix = 0x55;
uvar.uByte.foxi = 0xAA;
uvar.uBit.a = 1;
uvar.uBit.b = 0;

Nicht alle C-Compiler sehen das mit dem "uByte" und "uBit" gleich, es 
gibt ältere, bei denen muss man das weglassen.


matthias

von Benutzer N. (benutzername)


Lesenswert?

oder wie folgt :)
1
union uBYTE
2
{
3
  struct
4
  {   
5
    unsigned char byte;
6
  };
7
8
  struct
9
  {   
10
    unsigned b0:1;
11
    unsigned b1:1;
12
    unsigned b2:1;
13
    unsigned b3:1;
14
    unsigned b4:1;
15
    unsigned b5:1;
16
    unsigned b6:1;
17
    unsigned b7:1;
18
  };
19
};
20
21
22
23
struct Stuff
24
{
25
  uBYTE  fix;
26
  uBYTE  fox;
27
}myStuff;
28
29
30
void main()
31
{
32
33
  myStuff.fix.byte = 193;
34
35
  myStuff.fox.b4 = 1;
36
37
  printf("%d\n",myStuff.fix.byte);
38
  printf("%d %d %d %d %d %d %d %d \n",myStuff.fix.b7, myStuff.fix.b6, myStuff.fix.b5, myStuff.fix.b4, myStuff.fix.b3, myStuff.fix.b2, myStuff.fix.b1, myStuff.fix.b0);
39
40
}


das wäre dann genau gleich
1
193
2
1 1 0 0 0 0 0 1

von Werner B. (werner-b)


Lesenswert?

Nur als Hinweis:
Die Umsetzung einer Union ist aber Compiler- und Architekturspezifisch. 
Also nicht Sourcecode-Portabel.

von Tio T. (misterten)


Lesenswert?

Was soll
1
muh test;

bewirken? Was ist test? Also, der erste Beitrag des anonymen Freunds 
sieht schon so inetwa danach aus, was ich mir vorstelle. Ich erklär mal, 
was ich genau bezwecken wollte:

Bei Abschalten des uC sollen Werte ins EEPROM geschrieben werden. Da ich 
nun mehrere Variablen habe, die nur zwei Zustände haben können, macht es 
halt Sinn, diese als Bit zu deklarieren (in einer union macht auch 
Sinn).

Nun bin ich aber faul: Ich möchte jetzt nicht x Mal den Befehl 
__EEPROM_WRITE ausführen, sondern möchte nur eine als char deklarierte 
Variable ins EEPROM schicken. Und diese Variable soll dann die Werte in 
der union deklarierten Bits enthalten.

Warum dann nicht gleich nur die char Variable nehmen, und die 
entsprechenden Bits manipulieren!? Nun ja, es liest sich nicht gut. Das 
Programm ist ein wenig größer, und die Bits werden an den 
verschiedensten Stellen geändert. Und wenn ich an einer Stelle des 
Programms vertieft bin, weiß ich dann nicht mehr, an welchem Bit ich 
manipulieren muss.

Daher will ich den Bits jeweils einen Namen vergeben, so dass ich 
letztenendes nur benamten Bits manipuliere, und schlussendlich nur das 
Char (das diese Bits enthält) ins EEPROM schreibe.

Ich hoffe, ich denke da nicht zu umständlich?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Er meinte
1
union muh test;

Das ist eine Variablendefinition, wobei die Lösung von benutzername zwar 
nicht standardkonform, aber hübscher ist beim Hintexten des Zugriffs.

von Tobias P. (hubertus)


Lesenswert?

Du könntest auch für jedes Bit folgendes machen:

#define BIT0 0x01
#define BIT1 0x02
...
#define BIT7 0x80


und dann in deinem Code Dinge wie

var = BIT0 | BIT1 | BIT7;


schreiben um Bits zu setzen, oder

var ^= BIT0 | BIT 1;

um Bits umzukehren, oder

if(var & (BIT0 | BIT3 | BIT6))
...

um Bits zu prüfen und so weiter und so fort.
Bei der Windows-Programmierung wird das ähnlich gemacht. Der Befehl 
MessageBox z.B. kennt verschiedene Flags: MB_ICONEXCLAMATION (Dialogbox 
mit Ausrufezeichen-Symbol), MB_ICONINFORMATION (Dialogbox mit 
Info-Symbol), MB_OK (Dialogbox nur mit OK-Button) MB_YESNO (Dialogbox 
mit Ja und Nein Button). Im Code könnte man dann z.B. schreiben

MessageBox("Hallo Welt", MB_OK | MB_ICONINFORMATION);

Das würde eine Dialogbox mit dem Text "Hallo Welt", einem OK-Button und 
einem Info-Symbol anzeigen.
Mit diesen

#define BIT0 0x01

am Codeanfang kannst du für jedes Bit Namen vergeben und seine Position 
festlegen.
Der Vorteil ist klar:

1. Du hast die volle Kontrolle darüber, wo welches Bit steht.
2. Das funktioniert mit jedem Variablentyp (egal ob int, char, long, 
wasweissich).
3. Das funktioniert mit jedem Compiler.

Es wurde ja von meinen Vorgängern schon gesagt, dass nicht bei jedem 
Compiler int = 32 Bit ist und auch nicht jeder Compiler seine structs 
und unions gleich macht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tobias Plüss wrote:

> Es wurde ja von meinen Vorgängern schon gesagt, dass nicht bei jedem
> Compiler int = 32 Bit ist und auch nicht jeder Compiler seine structs
> und unions gleich macht.

Was aber nur dann berücksichtigt werden muss, wenn man die Daten binär 
zwischen unterschiedlichen Systemen überträgt.

Wenn man einen char mit 8 bit überlager, ist einem recht egal, wo diese 
stehen.

Ausserdem ist es dann wesentlich einfacher, ein Bit zu setzen:
1
foo.bit3 = 1;
2
foo.bit4 = 0;

Das rumbasteln mit Masken und und und oder und not und weil das nervt 
und noch ein set makro und noch ein clear und weil wir gerade dabei sind 
noch ein toggle und damits komplett ist ein test makro und...

von Tio T. (misterten)


Lesenswert?

Naja, ich will ja nicht zwischen Plattformen wandeln. Ich bin und bleibe 
beim 8-Bit uC, und ich weiß ja, was mein Compiler mit Unions anstellt.

Johann, das sieht prima aus. Und wenn ich nun einen bit 'uta' deklariert 
habe, wie definiere ich, dass bit 'uta' das bit 'foo.bit3' ist?

Ich denke
1
#define uta foo.bit3

alleine wird nicht funtionieren, da nicht definiert wurde, was 'uta' 
ist. Oder kann ich diese Deklaration einfach vorab setzen?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

#define mach nur Textersatz.

IMHO sollte man die sparsam verwenden. Man kann zwar Tipparbeit sparen, 
aber spätestens bei 3-fach verschachtelten Makros verfluchst du den 
Erschaffer...

In C gibt es keine Bits in Sinne wie Bytes (char) oder Worte (short). Es 
gibt nur Bitfelder, die sich aber von normalen Variablen unterscheiden: 
Man kann keine Arrays davon anlegen, keine Adressen bilden, etc.

In deinem Fall muss eben ein Objekt foo angelegt werden. Wie das geht 
steht oben
1
#ifndef FLAGS_H_
2
#define FLAGS_H_
3
#include <stdint.h>
4
5
typedef union
6
{
7
   struct
8
   {
9
       ...
10
       uint8_t uta:1;
11
   };
12
   ...
13
} flags_t;
14
15
extern flags_t foo;
16
#endif // FLAGS_H
~~~~~~~~~~~~~~~~~
1
#include "flags.h"
2
flags_t foo;
3
4
... foo.uta = 0;
5
... foo.orang = !foo.uta;

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.