Forum: PC-Programmierung ungenutztes Bitfeld (struct) mit 0 initialisiert oder undefiniert?


von Jonny O. (-geo-)


Lesenswert?

Hallo zusammen,

gegeben sei folgender Code:
1
#include <stdio.h>
2
3
typdef struct myStruct {
4
    unsigned int a: 4;
5
    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,

: Bearbeitet durch User
von Nikolaus S. (Firma: Golden Delicious Computers) (hns)


Lesenswert?

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...

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von Jonny O. (-geo-)


Lesenswert?

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.
28
29
    return 0;
30
}

von Nikolaus S. (Firma: Golden Delicious Computers) (hns)


Lesenswert?

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.

von Jonny O. (-geo-)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

Alte Programmierer-Weisheit: "Trau' keiner Variablen, die du nicht 
selber initialisert hast!". Ich würde mich daran halten ...

von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von MaWin O. (mawin_original)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

Jein. Der Wert der Padding-Bits ist undefined. Das kann alles bedeuten.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
> Jein. Der Wert der Padding-Bits ist undefined.

unspecified

von Bauform B. (bauformb)


Lesenswert?

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 :(

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.