Hallo, ich habe folgendes Problem. Ich erzeuge ein Union und möchte dieses gleiche initialisieren, dies schlägt aber aus mir nicht erklärlichen Gründen fehl. Ich hoffe der ein oder andere kann mir behilflich sein. Listing: typedef union { unsigned char all[2]; struct { unsigned char bit23:1; unsigned char bit22:1; unsigned char bit21:1; unsigned char bit20:1; unsigned char bit19:1; unsigned char bit18:1; unsigned char bit17:1; unsigned char bit16:1; unsigned char bit15:1; unsigned char bit14:1; unsigned char bit13:1; unsigned char bit12:1; unsigned char bit11:1; unsigned char bit10:1; unsigned char bit9:1; unsigned char bit8:1; unsigned char bit7:1; unsigned char bit6:1; unsigned char bit5:1; unsigned char bit4:1; unsigned char C3:1; unsigned char C2:1; unsigned char C1:1; unsigned char C0:1; }bits; struct { unsigned char byte0; unsigned char byte1; unsigned char byte2; }bytes; }Registers; Registers RDefault2[]={0x84,0,0x05,0x80,0,0x05} ; Fehlermeldung: pll.c:18: Warnung: geschweifte Klammern fehlen um Initialisierung pll.c:18: Warnung: (nahe der Initialisierung für "RDefault2[0]" Ausgabe des Unions ist: Byte0: 132 Byte1: 0 Byte2: 0 Byte0: 5 Byte1: 128 Byte2: 0 MFG Sebastian
Bist Du Dir sicher, dass der dargestellte Quell-Code dem Original entspricht? Die Ausgabe ist nicht mit Deiner Initialisierung identisch! Außerdem ist mir der Sinn Deiner Union noch nicht ganz klar. Wie groß ist das größte Element Deiner Union? 3? Dann würde ich die Initialisierung folgendermaßen schreiben: Registers RDefault2[] = {{0x84, 0, 0x05}, {0x80, 0, 0x05}}; Karsten
Ja, das ist der Original Code. Meine Ausgabe stimmt eben nicht. Das Größte Element ist 3, ja deine Schreibweise ist übersichtlicher, ändert aber nicht die Problemstellung. Für Abfrage benutze ich folgendes: Registers *ptr; ptr=RDefaults2; Test=ptr->bytes.byte0; usw.bis byte2 dann ptr++; und wieder das Gleiche. Liegt hier vieleicht der Fehler?? MFG Sebastian P.S. Mir ist bewußt dass char all[2] dass gleiche wie struct bytes macht. Ich wollte nur testen, ob das einen Unterschied bei meinem Problem macht.
>P.S. Mir ist bewußt dass char all[2] dass gleiche wie struct bytes >macht. Da ist schon mal ein Fehler drin: 'unsigned char all[2]' legt ein Array aus 'char' mit der Feldgröße 2 an, 'struct bytes' enthält aber derer drei.
...aus Spaß an der Freude: - main.c -
1 | #include <stdio.h> |
2 | |
3 | typedef union |
4 | {
|
5 | unsigned char all[2]; |
6 | |
7 | struct
|
8 | {
|
9 | unsigned char bit23:1; |
10 | unsigned char bit22:1; |
11 | unsigned char bit21:1; |
12 | unsigned char bit20:1; |
13 | unsigned char bit19:1; |
14 | unsigned char bit18:1; |
15 | unsigned char bit17:1; |
16 | unsigned char bit16:1; |
17 | unsigned char bit15:1; |
18 | unsigned char bit14:1; |
19 | unsigned char bit13:1; |
20 | unsigned char bit12:1; |
21 | unsigned char bit11:1; |
22 | unsigned char bit10:1; |
23 | unsigned char bit9:1; |
24 | unsigned char bit8:1; |
25 | unsigned char bit7:1; |
26 | unsigned char bit6:1; |
27 | unsigned char bit5:1; |
28 | unsigned char bit4:1; |
29 | unsigned char C3:1; |
30 | unsigned char C2:1; |
31 | unsigned char C1:1; |
32 | unsigned char C0:1; |
33 | }bits; |
34 | |
35 | struct
|
36 | {
|
37 | unsigned char byte0; |
38 | unsigned char byte1; |
39 | unsigned char byte2; |
40 | }bytes; |
41 | |
42 | }Registers; |
43 | |
44 | Registers RDefault2[]={{0x84},{0},{0x05},{0x80},{0},{0x05}}; |
45 | |
46 | int
|
47 | main(void) |
48 | {
|
49 | |
50 | int i = 0; |
51 | |
52 | for(i = 0; i < 6; i++) |
53 | printf("union #%d contains: " |
54 | "byte0=0x%02X byte1=0x%02X byte2=0x%02X\n", |
55 | i, |
56 | RDefault2[i].bytes.byte0, |
57 | RDefault2[i].bytes.byte1, |
58 | RDefault2[i].bytes.byte2); |
59 | |
60 | printf("Modifying member *.bits.C3\n"); |
61 | |
62 | RDefault2[1].bits.C3 = 1; |
63 | printf("union #1 contains: " |
64 | "byte0=0x%02X byte1=0x%02X byte2=0x%02X\n", |
65 | RDefault2[1].bytes.byte0, |
66 | RDefault2[1].bytes.byte1, |
67 | RDefault2[1].bytes.byte2); |
68 | |
69 | return 0; |
70 | }
|
Kompiliert mit: $ gcc -O -g -o union.exe main.c Ergibt folgendes: $ union union #0 contains: byte0=0x84 byte1=0x00 byte2=0x00 union #1 contains: byte0=0x00 byte1=0x00 byte2=0x00 union #2 contains: byte0=0x05 byte1=0x00 byte2=0x00 union #3 contains: byte0=0x80 byte1=0x00 byte2=0x00 union #4 contains: byte0=0x00 byte1=0x00 byte2=0x00 union #5 contains: byte0=0x05 byte1=0x00 byte2=0x00 Modifying member *.bits.C3 union #1 contains: byte0=0x00 byte1=0x00 byte2=0x10
Desweiteren: > struct > { > unsigned char byte0; > unsigned char byte1; > unsigned char byte2; > }bytes; das hier ist eine Struktur kein Bitfeld => du hast keine Garantie in welcher Reihenfolge byte0, byte1 und byte2 tatsächlich im Speicher liegen, die Wahrscheinlichkeit, dass sie genauso drin liegen, wie du es hinschreibst, ist zwar hoch, aber ein anderer Compiler (oder eine andere Compiler-Version) könnte das auch anders machen > P.S. Mir ist bewußt dass char all[2] dass gleiche wie struct bytes > macht. Ich wollte nur testen, ob das einen Unterschied bei meinem > Problem macht. du solltest aber nicht mit Quelltext experimentieren, der offensichtlich falsch ist - meines Wissens sind solch ein union einfach nicht definiert bzw. sollte dein Compiler meckern => dein Beispiel müsste undefiniertes Verhalten erzeugen > Registers RDefault2[]={0x84,0,0x05,0x80,0,0x05} ; Kann man unions überhaupt so initialisieren? woher soll der Compiler den Wissen, dass du die Darstellung als Struktur meinst? Funktioniert das: Registers RDefault2[2]; RDefault2[0].bytes = {0x84,0,0x05}; RDefault2[1].bytes = {0x80,0,0x05}; Ciao, Fabian
> das hier ist eine Struktur kein Bitfeld => du hast keine Garantie in > welcher Reihenfolge byte0, byte1 und byte2 tatsächlich im Speicher > liegen, Nicht nur das, auf manchen Systemen wird der Compiler zwischen den einzelnen 'bytex' Membern auch noch zusätzliche Padding Bytes einfügen um die Member wieder auf gerade Adressen liegen zu haben.
> das hier ist eine Struktur kein Bitfeld => du hast keine Garantie in > welcher Reihenfolge byte0, byte1 und byte2 tatsächlich im Speicher > liegen, ... Genau andersrum. Bei einem Bitfeld gäbe es keine Garantie für die Anordnung, aber nur in der Hinsicht, dass der Compiler die Elemente entweder auf- oder absteigend sortieren darf -- wild ,,verwürfeln'' darf er nicht. Bei einer Struktur ebenso: die Reihenfolge ist garantiert, nicht jedoch (wie Karl Heinz anmerkt) ein mögliches Auffüllen (Padding) zwischen den Elementen. Die aufsteigende Reihenfolge der Anordnung der Elemente einer Struktur im Speicher ist zwingend vorgeschrieben (6.7.2.1 Structure and union specifiers, Absatz 13). Zurück zur Initialisierung einer Union. In ANSI-C89/ISO-C90 kann man nur das erste benannte Element einer Union initialisieren (hier also all[2]). Da dieses selbst ein aggregate ist, benötigt es dabei zusätzliche geschweifte Klammern:
1 | Registers RDefault2[] = { |
2 | { 0x84 }, |
3 | { 0 }, |
4 | { 0x05 }, |
5 | { 0x80 }, |
6 | { 0 }, |
7 | { 0x05} |
8 | };
|
Ist das (6 Unions insgesamt, nur das erste Byte jeweils explizit initialisiert, der Rest implizit 0) eigentlich das, was du wolltest? Oder wolltest du eher
1 | Registers RDefault2[] = { |
2 | { 0x84, 0 }, |
3 | { 0x05, 0x80 }, |
4 | { 0, 0x05 }, |
5 | };
|
3 Unions insgesamt, jeweils beide Bytes von all[] initialisiert? Anyway, ISO-C99 gibt uns hier deutlich mehr Freiheiten. Jetzt geht sowas:
1 | Registers RDefault2[] = { |
2 | [2] = { |
3 | .all = { |
4 | [0] = 0x84, |
5 | [1] = 0x05, |
6 | },
|
7 | },
|
8 | [0] = { |
9 | .bytes = { |
10 | .byte0 = 0x42, |
11 | .byte2 = 0x05, |
12 | },
|
13 | },
|
14 | [1] = { |
15 | .bits = { |
16 | .bit8 = 1, |
17 | .bit11 = 1, |
18 | },
|
19 | },
|
20 | };
|
Man kann nur einen ,Zweig' der Union sinnvoll initialisieren, also nur entweder all, bytes oder bits. Gibt man mehrere an, so ,,gewinnt'' die letzte Variante, nicht etwa eine Überlagerung. Alle nicht angegebenen Initialisierungswerte werden dabei als 0 angenommen.
Hallo, danke für die vielen und schnellen Antworten ich werde sie sobald wie mgl. testen. >Da ist schon mal ein Fehler drin: 'unsigned char all[2]' legt ein >Array aus 'char' mit der Feldgröße 2 an, 'struct bytes' enthält >aber derer drei. Richtig, ich müsste 'unsigned char all[3]' schreiben, mein Fehler! Dank der sehr guten und detailierten Antwort von Jörg Wunsch erkennt man nun auch warum meine Ausgabe 'fehlerhaft' war. >Genau andersrum. Bei einem Bitfeld gäbe es keine Garantie für die >Anordnung, aber nur in der Hinsicht, dass der Compiler die Elemente >entweder auf- oder absteigend sortieren darf -- wild ,,verwürfeln'' >darf er nicht. Bei einer Struktur ebenso: die Reihenfolge ist >garantiert, nicht jedoch (wie Karl Heinz anmerkt) ein mögliches >Auffüllen (Padding) zwischen den Elementen. Wie verhält sich der avr-gcc in dieser Sache? Wo kann ich das nach lesen? Begebe mich mal auf die Suche. MFG Sebastian
> Wie verhält sich der avr-gcc in dieser Sache? Der AVR benötigt hardwaremäßig kein Padding (Ausnahme: Codezugriffe im ROM, die müssen auf 16 Bits ausgerichtet sein, Datenzugriffe jedoch nicht), insofern gibt's auch kein Padding innerhalb von Strukturen. Wenn der Code jedoch gleichzeitig mit dem GCC auf einer anderen Architektur (z. B. PC) compiliert werden soll, muss man vorsichtig sein. Zwischen unsigned chars gibt es dort auch kein Padding, jedoch zwischen einem unsigned char und einem Objekt, das größer ist. Das kann man mit __attribute__((packed)) verhindern. __attribute__((packed)) kann man übrigens auch nehmen, um die Größe eines enum von int auf den minimal notwendigen Platz einzuschränken. Allerdings ist mir aufgefallen, dass zumindest der GDB damit ein Problem hat, entweder bekommt er das in der Debug-Information nicht mitgeliefert oder er macht selbst die Annahme, dass siezof(enum X) == sizeof(int) sei.
Ein Blick in den Sourcecode der avr-libc, verrät auch warum Joerg sich so gut auskennt. ;-) MFG Sebastian
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.