unsigned int : 4; // unbenanntes (ungenutztes) Bitfeld
6
unsigned int b: 4;
7
}myStruct_t;
8
9
int main() {
10
myStruct_t myVar = { .a = 2, .b = 3 }; // unbenanntes Bitfeld mit 0 initialisiert, andere Bitfelder mit expliziten Werten?
11
//...
12
}
Wird in diesem Beispiel das ungenutzte Bitfeld mit 0 initialisiert? Oder
ist das undefiniert? Ich gehe mal davon aus, dass es undefiniert sein
wird. Gibt es da eine Möglichkeit ohne Zwischenschritt (also ohne vorher
das gesamte Struct mit 0 zu belegen und dann nochmal zuzuweisen)
explizite Werte für die benannten Felder zu vergeben und automatisch
alle ungenutzten Felder mit 0 zu initialisieren?
Danke und Grüße,
gehe mal sicherheitshalber davon aus, dass es uninitialisiert ist. Nicht
weil das eine spezielle Regel für bitfields wäre. Sondern weil myVar
eine lokale Variable ist, also auf dem Stack liegt. Nur globale
Variablen werden auf 0 vorinitialisiert (bzw. der gesamte
Speicherbereich in dem sie liegen).
Aber: wie willst Du ein unbenanntes und ungenutztes Bitfield überhaupt
abfragen, und wozu? Willst Du einen Zugriffs-Trick per *(int)&myVar
machen? Probiere es mit printf("%08x", *(int)&myVar) aus...
Der C99-Standard schreibt in Abschnitt 6.7.8
„ 21
If there are fewer initializers in a brace-enclosed list than there are
elements or members of an aggregate, or fewer characters in a string
literal used to initialize an array of known size than there are
elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage
duration.“
Also wird dein nicht explizit initialisiertes struct Element mit 0
initialisiert.
Oliver
Nikolaus S. schrieb:> gehe mal sicherheitshalber davon aus, dass es uninitialisiert ist.> Nicht> weil das eine spezielle Regel für bitfields wäre. Sondern weil myVar> eine lokale Variable ist, also auf dem Stack liegt. Nur globale> Variablen werden auf 0 vorinitialisiert (bzw. der gesamte> Speicherbereich in dem sie liegen).>> Aber: wie willst Du ein unbenanntes und ungenutztes Bitfield überhaupt> abfragen, und wozu? Willst Du einen Zugriffs-Trick per *(int)&myVar> machen? Probiere es mit printf("%08x", *(int)&myVar) aus...
Ich will Register eines Peripheriebausteines als typdef struct
defnieren. Im Baustein gibt es Register, bei denen teilweise ungenutzte
Bits vorkommen. Zwar ist es dem Baustein egal mit was man ihm an diesen
Stellen im Register beschreibt, aber ich möchte das gerne definiert mit
0 schreiben.
Hier mal ein Beispiel für ein 8-bit register, bei dem 3 bits des
Registers "reg" ungenutzt sind. Kann ich da sicherstellen, dass bei der
Printf ausgabe immer "10" rauskommt? Ich habe den Code jetzt mal nicht
auf einem Microcontroller laufen gehabt, sondern nur im C-Simulator. Da
kommt immer 10 raus, was aber natürlich nichts heißen muss.
1
#include <stdio.h>
2
#include <stdint.h>
3
4
5
typedef struct reg
6
{
7
uint8_t a: 3;
8
uint8_t b: 1;
9
uint8_t : 3;// - 3 bits im register sind unbenannt, da ungenutzt
10
uint8_t c: 1;
11
} reg_t;
12
13
reg_t myBits =
14
{
15
.a = 2,
16
.b = 1,
17
.c = 0
18
};
19
20
21
22
int main()
23
{
24
25
uint8_t myRegister = *(uint8_t*)&myBits;
26
27
printf("%u", myRegister); // myRegister ist ein Byte, das normalerweise der Routine übergeben wird, die das dann zum Baustein per SPI sendet.
Ja, so ähnlich habe ich das vermutet. Dann benenne das "unbenannte"
Bitfield einfach (z.B. undefined1:3) und initialisiere es explizit.
Wenn der Compiler gut ist, merkt er dass das gesamte struct definiert
wird und macht nur einen Initialisierungsbefehl draus. Du kannst auch
den Assemblercode anschauen was er daraus macht.
Nikolaus S. schrieb:> Ja, so ähnlich habe ich das vermutet. Dann benenne das> "unbenannte" Bitfield einfach (z.B. undefined1:3) und initialisiere es> explizit.> Wenn der Compiler gut ist, merkt er dass das gesamte struct definiert> wird und macht nur einen Initialisierungsbefehl draus. Du kannst auch> den Assemblercode anschauen was er daraus macht.
Okay danke! Ich war mir nicht sicher, ob es da irgendeine Möglichkeit
direkt bei der Initialisierung gibt. Dann werde ich die entsprechenden
Bitfelder einfach explizit mit Namen angeben und dann auf 0 setzen.
Nikolaus S. schrieb:> gehe mal sicherheitshalber davon aus, dass es uninitialisiert ist.> Nicht> weil das eine spezielle Regel für bitfields wäre. Sondern weil myVar> eine lokale Variable ist, also auf dem Stack liegt. Nur globale> Variablen werden auf 0 vorinitialisiert (bzw. der gesamte> Speicherbereich in dem sie liegen).
Ist in dem Fall egal. Sobald ein einziges Element eines struct
initialisiert wird, wird das ganze struct initialisiert, auch bei
lokalen Variablen.
Oliver
Jonny O. schrieb:> Im Baustein gibt es Register, bei denen teilweise ungenutzte> Bits vorkommen. Zwar ist es dem Baustein egal mit was man ihm an diesen> Stellen im Register beschreibt, aber ich möchte das gerne definiert mit> 0 schreiben.
Wenn du deiner C-Implementierung nicht traust, oder nur in so etwas
ähnlichem wie C programmierst, das nichts mit dem C-Standard zu tun hat,
dann gib dem unbenannten Element halt einen Namen, und weise dem die 0
explizit zu. Da ist ja nun wirklich kein Aufwand, und kann sogar noch
erklärend kommentiert werden.
Obwohl, dem Baustein ist’s egal, der Compiler macht’s sowieso, da klingt
das alles dann doch sehr nach - nun ja.
Oliver
Oliver S. schrieb:> Ist in dem Fall egal. Sobald ein einziges Element eines struct> initialisiert wird, wird das ganze struct initialisiert
Nein. Padding wird nicht initialisiert.
Jonny O. schrieb:> uint8_t myRegister = *(uint8_t*)&myBits;>> printf("%u", myRegister); // myRegister ist ein Byte, das> normalerweise der Routine übergeben wird, die das dann zum> Baustein per SPI sendet.
Wenn es sowieso so eine Routine gibt, und die am Ende sowieso ein
uint8_t braucht... dann könnte diese Routine das Problem mit einem
einzigen & lösen. Nebenbei könnte man den cast in der Routine
verstecken. Ich glaube, ich hab' die Frage nicht verstanden :(