Forum: Mikrocontroller und Digitale Elektronik Elemente eines struct inidizieren


von Jochen (Gast)


Lesenswert?

Hallo,

ich würde gerne unten stehende Strukturen sowohl über Ihren Namen 
ansprechen, als auch über Indizes. Damit will ich mir die Möglichkeit 
schaffen, die Daten in einer for-Schleife auf ein Display zuschreiben.
Für die bessere Lesbarkeit im Quelltext würde ich aber trotzdem gerne 
über ihren Namen auf die Strukturen zugreifen, also beispielsweise 
'L1.val'.

Direkt ein Array mit den Strukturen zu erzeugen, scheidet wohl aus, weil 
die Datentypen unterschiedlich lang sein können. Was ich mir aber 
vorstellen könnte, wäre ein weiteres Array, indem die Startadresse von 
jeder Struktur liegt. In der for-schleife könnte ich dann mittels 
pointer auf die jeweilige Struktur zugreifen. Ich überblicke gerade noch 
nicht, ob das funktionieren könnte und ist das ein vernünftiger und 
machbarer Weg, oder gibt es ein eleganteres herangehen?



[c]typedef struct{
       uint8_t pos_x;
       uint8_t pos_y;
       uint8_t visible;
       char   unit;
}TEXT;

typedef struct{
       TEXT Text;
       uint16_t val;
}DATA;

typedef struct{
       TEXT Text;
       uint16_t val;
       uint16_t val_tmp;
}EXTENDED;

DATA    L1={first_column,  bottom_row,  true, 'A', 0},
             L2={second_column, bottom_row,  true, 'A', 0},
             L3={third_column,  bottom_row,  true, 'A', 0},
             Imin={first_column,  second_row, true, 'A',0},
             Imax={third_column,  second_row, true, 'A',0};
EXTENDED   Time={second_column, second_row, true, 'M', 0, 0};/c


Vielen Dank

Jochen

von Karl M. (Gast)


Lesenswert?

Guten Morgen,

Stichwort # union{ }.
http://www2.informatik.uni-halle.de/lehre/c/c_union.html

von Ulrich F. (Gast)


Lesenswert?

Hmm...
Bei unterschiedlich langen Strukturen kann man verkettete Listen 
verwenden.
Ist aber mit Vorsicht zu genießen..
Dynamische Speicherverwaltung will man auf µC eigentlich nicht. Oder?

von Jochen (Gast)


Lesenswert?

Guten Morgen Karl,

vielen Dank für deine schnelle Antwort. Über unions bin ich gestern auch 
gestolpert. Habs aber noch nicht so gut verstanden, um es auch umsetzen 
zu können.

Kannst du mir noch einen kurzen Denkanstoß, bezogen auf mein Beispiel, 
geben?...das wäre nett.

Jochen

von Matthias L. (Gast)


Lesenswert?

>weil die Datentypen unterschiedlich lang sein können

Sowas existiert in den Objektverzeichnissen von CANopen.

Dort können die Datentypen auch unterschiedlich sein. Um das generisch 
intern zu handeln, wird (zB) die Startadresse der Struktur und die Länge 
jedes Members mitgegeben.

von Jochen (Gast)


Lesenswert?

mhm,

gibt es denn die Möglichkeit, die Strukturen anders aufzusetzen, damit 
ich beim automatisierten Zugriff immer auf die gleiche Länge zugreife?

von Matthias L. (Gast)


Lesenswert?

>ich beim automatisierten Zugriff immer auf die gleiche Länge zugreife?

Dann musst Du Füllbytes einsetzen und alles auf gleiche maximale Länge 
auffüllen. Das Problem bleibt aber noch, das Du nicht weisst, wielang 
das Element wirklich ist.

von Hans-Georg L. (h-g-l)


Lesenswert?

Die verschiedenen Strukturen auf die gleiche Länge bringen ist nur die 
halbe Miete. Du hast zwar dann alles schön in einem Array aber du willst 
ja auch auf die verschiedenen Member der Strukturen zugreifen und da 
muss du den Typ der Struktur mitführen damit du auf die richtige 
Struktur casten kannst.

Also entweder mit union und mit zusätzlichem type member oder mit einer 
zusätzlichen struktur

typedef struct {
   uint8_t type;  // DATA = 0, EXTENDED = 1, ...
   void*   data;
} UNIDATA;

von Jochen (Gast)


Lesenswert?

Hallo,

ich komme nicht dahinter wie mir unions bei der Indizierung helfen 
könnten. Ich hätte wohl auch nicht zwei Schritte auf einmal tun 
sollen.:-) Vielleicht ist es mit einer einzelnen Struktur einfacher zu 
begreifen.
1
typedef struct{
2
       uint8_t pos_x;
3
       uint8_t pos_y;
4
       uint8_t visible;
5
       char   unit;
6
}DATA;

jetzt kann ich:
1
DATA L1, L2, L3, Imax, Imin;
2
L1.pos_x = 0x00;

oder eben:

1
DATA a[5];
2
a[0].pos_x = 0x00;

Soweit verstehe ich, aber wie schaffe ich es jetzt mit Hilfe von unions 
den Zugriff auf beide Arten zu realisieren?

von Fritz Katze (Gast)


Lesenswert?

Denkanstoß:

Statt eines Array von struct kann man ja ein struct von Arrays nehmen.

struct {

int feld1[1000];
byte feld2[2000];

};

von Karl H. (kbuchegg)


Lesenswert?

Jochen schrieb:

> Soweit verstehe ich, aber wie schaffe ich es jetzt mit Hilfe von unions
> den Zugriff auf beide Arten zu realisieren?

mit einer union legst du über denselben Speicherbereich eine andere 
Datenstruktur drüber.
Aber Achtung: offiziell ist das nur im Ausnahmefall erlaubt, dass du zb 
ein unsigned char Array über den Speicher legst.
Trotzdem ist diese Technik seit Jahrzehnten gang und gäbe.
1
typedef struct{
2
       uint8_t pos_x;
3
       uint8_t pos_y;
4
       uint8_t visible;
5
       char   unit;
6
}DATA;
7
8
union Data_t
9
{
10
  DATA     d;
11
  uint8_t  bytes[4];
12
};
13
14
Data_t meineDaten;

meineDaten.d und meineDaten.bytes liegen im Speicher übereinander.
1
   meineDaten.d.posx = 5;
2
3
   i = meineDaten.bytes[0];    // i kriegt den Wert 5

von Karl H. (kbuchegg)


Lesenswert?

Eine etwas andere Mögllichkeit wäre zb das Arbeiten mit dem Präprozessor 
:-)
Immer daran denken. Wenn dir im Quelltext irgendetwas textuell nicht 
gefällt, dann gibt es oft Mögllichkeiten wie du mit dem Präprozessor 
eine alternative Schreibweise erzielen kannst.

Du hast zb ein Array
1
uint8_t daten[5];

um auf das Element mit dem Index 1 zuzugreifen, müsstest du schreiben
1
   daten[1] = 8;

jetzt möchtest du aber nicht [1] schreiben, weil dir das zuwenig 
aussagekräftig ist. Statt dessen möchtest du zb lieber
1
    daten[Y_POS] = 8;
schreiben können.
(Gewöhn dir am besten gleich an, dass du derartige Text-Magie immer in 
Grossbuchstaben und ausschliesslich in Grossbuchstaben schreibst. Und 
auch umgekehrt: ausschliesslich Grossbuchstaben bedeutet, dass es sich 
um ein Präprozessormakro handelt)

Um das gewünschte zu erreichen, würde es genügen, wenn vor dem 
Compilerlauf irgendjemand den Text Y_POS gegen den Text 1 austauscht.

Na genau das kann aber der Präprozessor. SChreibst du dir ein Makro
1
#define Y_POS     1
dann passiert genau das: Der Präprozessor sieht die Zeile
1
   daten[Y_POS] = 8;
und weil er das Makro
1
#define Y_POS   1
vorher schon gesehen hat, tauscht er den Text Y_POS gegen den Text 8 
aus. Als Ergebnis entsteht
1
   daten[1] = 8;
das erstens genau so beabsichtigt war und das zweitens dann zum 
eigentlichen Compiler geht, der es übersetzt.

von Jochen (Gast)


Lesenswert?

Hallo Karlheinz,

das verstehe ich dann, aber dann muss ich doch trotzdem bei einem 
gezielten Zugriff den index kennen. Ich möchte ja doch mehrere Variablen 
vom typ DATEN erzeugen

1
typedef struct{
2
       uint8_t pos_x;
3
       uint8_t pos_y;
4
       uint8_t visible;
5
       char   unit;
6
}DATA;
7
8
union Data_t
9
{
10
  DATA     d[4];
11
  uint8_t  bytes[4*4];
12
};
13
14
Data_t meineDaten;

...und der Zugriff dann so
1
meineDaten.d[2].posx = 5;
2
3
   i = meineDaten.bytes[3*4];

von Hannes (Gast)


Lesenswert?

Karl H. schrieb:
> und weil er das Makro
> #define Y_POS   1
> vorher schon gesehen hat, tauscht er den Text Y_POS gegen den Text 8
> aus. Als Ergebnis entsteht
> daten[1] = 8;

Wäre das dann nicht
daten[8] = 8;
?

von Karl H. (kbuchegg)


Lesenswert?

Jochen schrieb:
> Hallo Karlheinz,
>
> das verstehe ich dann, aber dann muss ich doch trotzdem bei einem
> gezielten Zugriff den index kennen.

Logisch. So funktioniert nun mal ein Array.

> Ich möchte ja doch mehrere Variablen
> vom typ DATEN erzeugen

Du erzeugst dann eben nicht vom Typ Daten, sondern vom Typ Data_t

Entweder du willst etwas erreichen, dann musst du auch den Aufwand dafür 
schlucken.
Oder du lässt es.

C ist nun mal eine statisch typisierte Sprache. Zur Laufzeit ist 
keinerlei Information mehr vorhanden, was das da im Speicher darstellen 
soll.
Das hat Vorteile, zum Beispiel den, dass du die Kontrolle darüber hast, 
was im Speicher angelegt wird und was nicht.
Das hat aber auch Nachteile. So etwas wie Reflection ist in C aus dem 
Stand heraus nicht möglich, sondern man muss es sich selbst 
programmieren, wenn man das möchte.

Umsonst ist der Tod. Und der kostet das Leben.

von Jochen (Gast)


Lesenswert?

...deinen zweiten Post habe ich nicht gesehen...die Kombination aus 
beiden wäre wohl möglich:

1
#define L1  0;
2
#define L2  1;
3
#define L3  2;
4
5
6
meineDaten.d[L1].posx = 5;
7
8
int i;
9
meineDaten.d[i].posx = 5;

...dafür brauche ich aber doch dann keine unions und auch keine struct 
von arrays

von Karl H. (kbuchegg)


Lesenswert?

Hannes schrieb:
> Karl H. schrieb:
>> und weil er das Makro
>> #define Y_POS   1
>> vorher schon gesehen hat, tauscht er den Text Y_POS gegen den Text 8
>> aus. Als Ergebnis entsteht
>> daten[1] = 8;
>
> Wäre das dann nicht
> daten[8] = 8;
> ?

Der Tippfehler sitzt hier
> tauscht er den Text Y_POS gegen den Text 8

Der wird natürlich nicht gegen 8 sondern gegen 1 getauscht. Das Makro 
war ja schliesslich
1
#define Y_POS   1

danke für den Hinweis auf den Tippfehler

von Karl H. (kbuchegg)


Lesenswert?

Jochen schrieb:
> ...deinen zweiten Post habe ich nicht gesehen...die Kombination aus
> beiden wäre wohl möglich:
>
>
>
1
#define L1  0;
2
> #define L2  1;
3
> #define L3  2;

immer wieder gerne gemacht dieser Fehler

Beim Präprozessort handelt es sich im Grunde genommen um einen 
Texteditor
WEnn du schreibst
1
 #define L2  1;

dann wird der Text 'L2' gegen den Text '1;' ausgetauscht.

aus
1
  meineDaten.d[L2].posx = 5;

wird dann
1
  meineDaten.d[L2;].posx = 5;

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.