Forum: Compiler & IDEs union-Frage


von beta-frank (Gast)


Lesenswert?

Hallöchen,

eine union kann man ja gut benutzen für so etwas in der Art:

typedef struct{
  U8 x; //Koordinate
  U8 y; //Koordinate
}point_t;

typedef union{
  U16 alle;
  point_t einzeln;
}xy_u;

xy_u xy;
xy.einzeln.x = 3;
xy.einzeln.y = 4;
mach_irgendwas(xy);
xy.alle = 0;  //Alle auf einen Streich gelöscht

Aber wie stelle ich das beispielhaft für nachfolgendes an?

typedef struct{
  U8 x; //Koordinate
  U8 y; //Koordinate
  U8 z; //Koordinate
}point_t;

typedef union{
  U24 alle; //3-byte gibts aber nicht...!
  point_t einzeln;
}xyz_u;

Da die union wiederum in einer längeren Tabelle verwendet wird, möchte
ich nicht z.B. U32 verbraten, wenn theoretische U24 reichen würde.

typedef struct{
   xyz_u   xyz;
   U8      foo;
}table_t;

table_t table[] = {/* viele Einträge*/};

von Wolfgang Horn (Gast)


Lesenswert?

Hi, Frank-in-der-Beta-Version :-)

was sagt Dein Assembler-Listing? Legt der Compiler structs mit 1* u16
und 1* u8-Variablen lückenlos an, oder läßt er sowieso eine Lücke?
Ist das progmem-Konstanten genauso wie bei RAM und EEPROM?

Falls er structs mit einer ungeradzahligen Anzahl u8 lückenlos packt,
wüßte ich keine bessere Lösung als die Tabelle als point_t liste[] zu
speichern und die union xy_u nur innerhalb einer Funktion zu
deklarieren.

Ciao
Wolfgang Horn

von Karl H. (kbuchegg)


Lesenswert?

Hi beta-frank

> eine union kann man ja gut benutzen für so etwas in der Art:

Mach das nicht.
In diesem Fall kannst du wie folgt vorgehen:

point_t xy;

xy.x = 0;
xy.y = 0;

oder meinetwegen

xy.x = xy.y = 0;

aber geh nicht den Weg über eine union. Würde mich sehr wundern
wenn das langsamer oder schneller wäre als die Zuweisung über
die union.
Selbst die Verwendung einer union um einen bestimmten Datentyp in
Bytes aufzudröseln ist genau genommen vom C-Sprachstandard nicht
gedeckt. Deine Variante ist weit davon entfernt auch nur ansatzweise
legal zu sein.

Wenn du unbedingt eine Struktur in einem Rutsch auf
alle Bytes 0 setzen willst, dann mach das so:

   memset( &xy, 0, sizeof( xy ) );

das ist legal und funktioniert auch dann, wenn der Compiler
Padding benutzt. Das Monster kannst du, wenn du willst noch
in einem schicken Makro verpacken:

#define CLEAR(x)  memset( &(x), 0, sizeof( x ) )

und damit schreiben:

  point_t xy;
  CLEAR( xy );

von beta-frank (Gast)


Lesenswert?

Danke für Eure Antworten! Wenn ich über das beta-Stadium schon hinaus
wäre, bräuchte ich ja nicht fragen;-))

Ich versuche, nochmal genauer zu erklären was ich erreichen möchte:

Ich bekomme 6 U8 Werte nacheinander, die ich einzeln und nacheinander
ermittle und erstmal in einer Structvariablen ablege/sammle. Es gibt
nur rund 20 verschiedene Kombinationen der 6 Werte, welche ich nun
mittels einer Tabelle ermitteln will (und dann die entsprechene
Callback aus 20 möglichen Callbacks aufrufen kann).

Das ganze darf aber auch nicht allzu viel Rechenzeit benötigen. Mein
nächster Ansatz ist nun (Beispielhaft wieder mit 3 U8-Variablen)
1
typedef struct{
2
  U8 x; //Koordinate
3
  U8 y; //Koordinate
4
  U8 z; //Koordinate
5
}point_t;
6
7
typedef struct{
8
   point_t xyz;
9
   PFKT    pfkt;  //Funktionszeiger auf Callback
10
}table_t;
11
12
table_t table[] = {
13
  {{1,2,3},callback_1},
14
  {{7,8,9},callback_2},
15
};
16
17
void main(void){
18
  point_t live={7,8,9};
19
  U8 cnt;
20
  for(cnt=0; cnt<sizeof(table)/sizeof(table_t); ++cnt)
21
    if( strncmp((char*)&table[cnt], (char*)&live, sizeof(point_t))==0)
22
      table[cnt].pfkt();//TabellenÜbereinstimmung gefunden
23
}

Würde mich über einen Kommentar / Verbesserungsvorschlag freuen.

Frank

von beta-frank (Gast)


Lesenswert?

PS:
das sinnvlolle
1
break;
, um in der for-Schleife nicht unnötig länger zu weilen liefere ich
hiermit nach;-)

von Karsten Brandt (Gast)


Lesenswert?

Hi Frank,

ich wage zu bezweifeln, das Du mit einem String-Vergleich den korrekten
Punkt in Deiner Tabelle findest!

besser?:
1
typedef struct{
2
  U8 x; //Koordinate
3
  U8 y; //Koordinate
4
  U8 z; //Koordinate
5
}point_t;
6
 
7
typedef struct{
8
   point_t xyz;
9
   PFKT    pfkt;  //Funktionszeiger auf Callback
10
}table_t;
11
 
12
table_t table[] = {
13
  {{1,2,3},callback_1},
14
  {{7,8,9},callback_2},
15
};
16
 
17
bool equalPoints(point_t p1, point_t p2)
18
{
19
  return ( ( p1.x == p2.x ) &&
20
           ( p1.y == p2.y ) &&
21
           ( p1.z == p2.z ) );
22
}
23
24
void main(void){
25
  point_t live={7,8,9};
26
  U8 cnt;
27
  for(cnt=0; cnt<sizeof(table)/sizeof(table_t); ++cnt)
28
    if( equalPoints(table[cnt].xyz, live)
29
      table[cnt].pfkt();//TabellenÜbereinstimmung gefunden
30
}

von Karl heinz B. (kbucheg)


Lesenswert?

> ich wage zu bezweifeln, das Du mit einem String-Vergleich den
> korrekten Punkt in Deiner Tabelle findest!

Yep.

@Frank
Die Idee die du hattest, ist doch dass alle Bytes
identisch sein muessen.
Hier reden wir von Bytes, d.h. die str... Funktionen
sind keine gute Wahl. Unter anderem deshalb da bei
Strings es ja einen Bytewert mit einer ganz bestimmten
Bedeutung gibt. Das 0-Byte und es bedeutet  'End of String'.
Alle str... Funktionen wissen das und behandeln das auch
entsprechend.

Wenn du auf Byte-Ebene arbeitest: mem... Funktionen
Wenn die Bytes zusätzlich noch die Vorausssetzungen für
einen String erfüllen: str... Funktionen

Oder aber das ganze klassisch ausprogrammieren, so wie Karsten
das vorschlägt.

von beta-frank (Gast)


Lesenswert?

Die Variante
1
bool equalPoints(point_t p1, point_t p2)
2
{
3
  return ( ( p1.x == p2.x ) &&
4
           ( p1.y == p2.y ) &&
5
           ( p1.z == p2.z ) );
6
}
werde ich verwenden. Ich dachte, strncmp(..) (ausgesprochen vermutlich
String_N_Compare) vergleicht stur N zeichen ohne auf '\0' zu achten.
Achtet sie aber...

Vielen Dank für Eure Unterstützung!

Frank

von Karl heinz B. (kbucheg)


Lesenswert?

> Ich dachte, strncmp(..) (ausgesprochen vermutlich
> String_N_Compare) vergleicht stur N zeichen ohne auf '\0' zu
achten.

strncmp benutzt man gerne zum Parsen wenn man eine Eingabezeile
hat und zb. weiss dass die mit einem bestimmten Schlüsselwort
anfangen muss.
zb. Hast du ein Protokoll
POINT 2, 20, 30, 40
LINE 5, 6

Um jetzt festzustellen ob das eine POINT oder eine LINE
Zeile ist, kannst du machen:

   if( strncmp( Input, "POINT", 5 ) == 0 )
     // war ein POINT

   else if( strncmp( Input, "LINE", 4 ) == 0 )
     // war ein LINE

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.