Forum: Mikrocontroller und Digitale Elektronik Problem mit struct und union


von Martin G. (hb9tzw)


Lesenswert?

Hallo

Wäre cool wenn mir jemand sagen könnte, was an diesem Code hier nicht 
korrekt ist:
1
typedef union {
2
   unsigned short u16;
3
   struct {
4
      unsigned char lowbyte : 8;
5
      unsigned char highbyte : 8;
6
   } byte;
7
   struct {
8
      unsigned char b0 : 1;
9
      unsigned char b1 : 1;
10
      unsigned char b2 : 1;
11
      unsigned char b3 : 1;
12
      unsigned char b4 : 1;
13
      unsigned char b5 : 1;
14
      unsigned char b6 : 1;
15
      unsigned char b7 : 1;
16
   } bit;
17
} FontType;
18
19
struct {
20
   FontType Header;
21
   unsigned short *Data;
22
   unsigned char Width;
23
   unsigned char Height;
24
   unsigned char Style;
25
   unsigned char LetterSpacing;
26
   unsigned char NumberOfChars = Header.byte.highbyte;
27
   unsigned char IsFixed = Header.bit.b0;
28
   unsigned char IsVariable = Header.bit.b1;
29
   unsigned char IsScanX = Header.bit.b6;
30
   unsigned char IsScanY = Header.bit.b7;
31
   unsigned char IsExtendedHeader = Header.bit.b3;
32
} TFont;

Es geht darum, Code von Basic nach C zu übersetzen, wobei der 
Basic-Compiler schon Funktionen zum Zugriff auf High-/Lowbyte und 
einzelne Bits eingebaut hat. TFont existierte entsprechend schon, so 
dass ich mir etwas einfallen lassen muss, um das so ähnlich wie möglich 
in C beibehalten zu können.

Jedenfalls wirft der Compiler im TFont-Struct auf den Zeilen, wo ich die 
FontType-Variable Header verwende, einen Fehler dieser Art:

../Graphics.c:186: error: expected ':', ',', ';', '}' or '__attribute__' 
before '=' token

Vielen Dank.

Grüsse
Martin

P.S.: Eine weitere Frage brennt mir auch schon unter den Nägeln: Wenn 
das Problem oben gelöst ist, wie greife ich dann auf die 
Pointer-Variable zu? *Font.Data?

von Gerhard (Gast)


Lesenswert?

Hi

ich hab die obige Definition mal im Borland C++ Builder eingefügt. Der 
Borland meckert das hier an:

   unsigned char NumberOfChars = Header.byte.highbyte;
   unsigned char IsFixed = Header.bit.b0;
   unsigned char IsVariable = Header.bit.b1;
   unsigned char IsScanX = Header.bit.b6;
   unsigned char IsScanY = Header.bit.b7;
   unsigned char IsExtendedHeader = Header.bit.b3;

"Zuweisung von Werten während der Definition nicht möglich."

Zugriff würde erfolgen: TFiont.Header.u16 = 0; z.B.
Da es innerhalb vom Borland C++ Builder schon ein "TFont" gibt, ist eine 
Variable oder Definition von TFont ungünstig. Müsste also bei Borland 
idealerweise anders heissen.

Gruß
Gerhard

von Martin G. (hb9tzw)


Lesenswert?

Ja genau, AVR-GCC meckert nur bei der ersten der von dir erwähnten 
Zeilen, wenn man die auskommentiert bei der nächsten etc...

Was heisst das jetzt genau? Sorry da komm ich nicht selbst drauf, kann 
ein Spezi mir bitte den entschedenden Hinweis geben, danke.

Gruss
Martin

von Grrrr (Gast)


Lesenswert?

Martin Geissmann schrieb:
> Was heisst das jetzt genau?
Was heisst was?

Beziehst Du Dich auf
> "Zuweisung von Werten während der Definition nicht möglich."
Was verstehst Du daran nicht?

von Star K. (starkeeper)


Lesenswert?

Das ist doch ziemlich einfach, du kannst in einer Typdefinition keine 
Werte zuweisen!
Diese Zeilen sind alle falsch:
1
   unsigned char NumberOfChars = Header.byte.highbyte;
2
   unsigned char IsFixed = Header.bit.b0;
3
   unsigned char IsVariable = Header.bit.b1;
4
   unsigned char IsScanX = Header.bit.b6;
5
   unsigned char IsScanY = Header.bit.b7;
6
   unsigned char IsExtendedHeader = Header.bit.b3;

von Oliver (Gast)


Lesenswert?

>Was heisst das jetzt genau? Sorry da komm ich nicht selbst drauf, kann
>ein Spezi mir bitte den entschedenden Hinweis geben, danke.

Datt jeht in C und auch in C++, und eigentlich auch sonst grundsätzlich, 
so nicht. Du versuchst, einer Variablen einen Wert aus einer anderen 
Variablen zuzuweisen, obwohl diese andere noch gar nicht initialisiert 
ist.

Das wird so auch in Basic nicht gehen, da wirst du ein paar Zeilen 
Programmcode basteln müssen.

Der C-Compiler meckert allerdings aus einem anderen Grund:

Variablen lassen sich in C während der Deklaration nur mit Konstanten 
initialisieren, und Konstanten meint da wirklich Konstanten im Sinne von 
42.

C++ würde auch constant deklarierte Variablen akzeptieren, aber nichtmal 
so etwas hast du vorliegen.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Ausserdem ist die ganze Vorgehensweise, sofern ich die Absicht dahinter 
richtig interpretiere, mehr als zweifelhaft (auch wenn das gültiges C 
wäre).

Man speichert nicht dieselbe Information 2 mal in einer Datenstruktur! 
Niemals.

Erstens ist es Platzverschwendung
Zweitens hat man immer das Problem, dass die beiden Informationsträger 
auseinanderlaufen können und dann stellt sich die Frage: Welche gilt 
denn jetzt?

Schmeiss die Member NumberOfChars, IsFixed, IsVariable, IsScanX, IsScanY 
und IsExtendedHeader aus der struct raus und ersetze sie durch 
Zugriffsfunktionen, die sich die relevanten Werte direkt aus Header 
holen bzw. dort ablegen.

von Heinz Heizer (Gast)


Lesenswert?

Das ist doch ein Union, da greift er doch auf den gleichen 
Speicherbereich zu, oder nicht?

von Karl H. (kbuchegg)


Lesenswert?

Heinz Heizer schrieb:
> Das ist doch ein Union, da greift er doch auf den gleichen
> Speicherbereich zu, oder nicht?

Nö.

Die Idee, so wie ich das aus dem Code rauslese, ist es einen Member 
Header zu haben, in dem alles drinnen ist.

struct {
   FontType Header;


Und irgendwie magisch sollen sich die Member

   unsigned char NumberOfChars = Header.byte.highbyte;
   unsigned char IsFixed = Header.bit.b0;
   unsigned char IsVariable = Header.bit.b1;
   unsigned char IsScanX = Header.bit.b6;
   unsigned char IsScanY = Header.bit.b7;
   unsigned char IsExtendedHeader = Header.bit.b3;

magisch an diesem Header bedienen und einzelne Informationen daraus in 
neuen Members magisch zur Verfügung stellen.

Das hat erst mal nichts mit der Union an sich zu tun

struct {
  int i;
  int j = i;
}

wäre eine kürzere Version mit genau der gleichen Grundidee.
Das das so in C nichts wird, dürfte klar sein. Da wird wohl in BASCOM 
ein Alias gestanden haben. Den muss man aber in C anders implementieren.

von Andreas K. (scavanger)


Lesenswert?

Ja, aber warum macht ersich erst eine union, nur um sie dann gleich 
wieder in einer structure  zu verwenden? Das ist das doppelte was Kar 
heinz meint.

Ausserdem, wenn man schon eine Struktur will und sie gleich 
initialisieren will dann bitte so:
1
struct Struktur{
2
      int foo;
3
      char name[10];  
4
} myStruct = {42, "Wilma"};

von Eddy C. (chrisi)


Lesenswert?

>Ja, aber warum macht ersich erst eine union, nur um sie dann gleich
>wieder in einer structure  zu verwenden? Das ist das doppelte was Kar
>heinz meint.

Weil das mit dem union noch nicht richtig angekommen ist.

Ein Auszug aus dem Original Basic-Source wäre angenehm. Letztlich läuft 
es auf sowas hinaus:

struct {
   unsigned char Width;
   unsigned char Height;
   unsigned char Style;
   unsigned char LetterSpacing;
   unsigned char NumberOfChars;

   // Alles in einem Byte
   unsigned char IsScanY : 1;
   unsigned char IsScanX : 1;
   unsigned char Unused : 3;
   unsigned char IsExtendedHeader : 1;
   unsigned char IsVariable : 1;
   unsigned char IsFixed : 1;
} THeader;

struct {
   struct THeader Header;
   unsigned short *Data;
} TFont;

von Martin G. (hb9tzw)


Lesenswert?

Ich poste euch hier wie gewünscht mal noch den original Basic-Code 
(nicht Bascom):
1
Public Structure TFont
2
   Header As Word
3
   Data As Word
4
   Width As Byte
5
   Height As Byte
6
   Style As Byte
7
   LetterSpacing As Byte
8
   NumberOfChars As Header.Byte1
9
   IsFixed As Header.Booleans(0)
10
   IsVariable As Header.Booleans(1)
11
   IsScanX As Header.Booleans(6)
12
   IsScanY As Header.Booleans(7)
13
   IsExtendedHeader As Header.Booleans(3)
14
End Structure

Die Byte1 und Booleans-Makros stehen hier offenbar schon zur Verfügung.

Wie gesagt, es ging mir darum, dass ich in C genau gleich auf die Daten 
zugreifen kann wie im Originalprogramm, egal ob es schönes C ist oder 
nicht. Wahrscheinlich kommen da aber noch viele weitere Probleme hinzu, 
so dass wohl nichts daraus wird.

Gruss
Martin

von Oliver (Gast)


Lesenswert?

Nun ja, du wirst zunächst mal verstehen müssen, was der Basic-Code da 
wirklich bedeutet. Dann lässt sich sowas auch in C nachbauen.

Meine Vermutung ist die, daß da tatsächlich eine Art union entsteht, die 
das header-byte zusätzlich in einzelne bits auflöst. Etwa in der Art:
1
typedef struct {
2
   uint16_t header;
3
   uint16_t data;
4
   uint8_t Width;
5
   uint8_t Height;
6
   uint8_t Style;
7
   uint8_t LetterSpacing;
8
   uint8_t NumberOfChars;
9
} TFont;
10
11
typedef struct {
12
   // Alles in einem Byte
13
   unsigned char IsScanY : 1;
14
   unsigned char IsScanX : 1;
15
   unsigned char Unused : 3;
16
   unsigned char IsExtendedHeader : 1;
17
   unsigned char IsVariable : 1;
18
   unsigned char IsFixed : 1;
19
} Booleans ;
20
21
typedef union {
22
   TFont myFont;
23
   Booleans myBooleans;
24
} myUnion;

Oliver

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.