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
Die Strukturen in eine Union packen.
Ach, d.h. ich würde es so schreiben:
union fix
{ unsigned a:1;
unsigned b:1;
unsigned c:1;
};
?
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!
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
Viel Spaß damit ;)
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
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
Nur als Hinweis:
Die Umsetzung einer Union ist aber Compiler- und Architekturspezifisch.
Also nicht Sourcecode-Portabel.
Was soll
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?
Er meinte
Das ist eine Variablendefinition, wobei die Lösung von benutzername zwar
nicht standardkonform, aber hübscher ist beim Hintexten des Zugriffs.
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.
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...
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
alleine wird nicht funtionieren, da nicht definiert wurde, was 'uta'
ist. Oder kann ich diese Deklaration einfach vorab setzen?
#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.
|