Forum: Mikrocontroller und Digitale Elektronik Iteration über Struct


von Third E. (third-eye)


Lesenswert?

Hallo,

nach Lesen des Threads Beitrag ""Zeiger" auf struct-Element" 
stellt sich mir die Frage, ob der untenstehende Code empfehlenswert ist?
Speziell der Cast auf (TFilterStruct*).

Ein ähnlicher Code läuft auf einem 8Bit-µC, nur habe ich dort ein Array 
aus TFilterStruct erstellt und rufe die einzelnen Arrayelemente über 
einen Index (Enum) auf. Das funktioniert problemlos, nur ist es beim 
Debuggen immer sehr umständlich, weil ich da nur Zahlen als Index sehe. 
Dann muss ich erst immer nachzusehen, welcher "sprechende" Enum-Wert 
denn der Zahl entspricht.

Ich habe den Code abgeändert und ein kleines C-Programm für den PC zur 
besseren Evaluierung erstellt.
Ich verwende jetzt ein Struct bestehend aus Structs.

Ich möchte sowohl auf bestimmte Elemente zugreifen können (wie bei der 
Dummy-Initialisierung) als iterieren (wie in der for-Schleife).

Weiterhin stellt sich mir die Frage: Könnte man die for-Schleife zwecks 
Optimierung des Speicherverbrauchs (kleiner µC!) gleich den Pointer 
initialisieren bzw. iterieren?

Man beachte übrigens auch die Dummy-Werte, von oben nach unten gelesen. 
:-D

Grüße
Third Eye

1
#include <stdio.h>
2
#include <conio.h>
3
#include <stdint.h>
4
5
typedef struct
6
{
7
   uint16_t InputValue;
8
   float FilteredValue;
9
   uint8_t FlagInputValueReadyToProcess;
10
} TFilterStruct;
11
12
13
static struct
14
{
15
   TFilterStruct U1Max;
16
   TFilterStruct U2Max;
17
   TFilterStruct U1Avg;
18
   TFilterStruct U2Avg;
19
}
20
FilterStructAll = {0};
21
22
23
int main(void)
24
{
25
   //Dummy-mäßig auf irgendwelche Werte setzen:
26
   FilterStructAll.U1Max.InputValue = 0xBAD;
27
   FilterStructAll.U2Max.InputValue = 0xDEAF;
28
   FilterStructAll.U1Avg.InputValue = 0xACDC;
29
   FilterStructAll.U2Avg.InputValue = 0xBABE;
30
31
   TFilterStruct* Ptr = (TFilterStruct*)&FilterStructAll;
32
   for (uint8_t i = 0; i < sizeof(FilterStructAll) / sizeof(TFilterStruct); i++)
33
   {
34
      printf("%X\r\n", Ptr->InputValue);
35
      Ptr++;
36
   }
37
38
   printf("Ende.\r\n");
39
   getch(); //Auf "Enter" warten.
40
   return 0;
41
}

von Dumdi D. (dumdidum)


Lesenswert?

Der Code ist nicht sicher. Es ist meiner Meinung nach nicht garantiert, 
dass zwischen den TFilterStructs keine Füllbytes angelegt werden. (Und 
damit springt der Ptr++ zu kurz).

Warum legst Du kein Array mit TFilterStructs an?

von Tom (Gast)


Lesenswert?

Direkt im Speicher herumzumachen und als Nebenwirkung die passenden 
(oder wie hier dank Padding die nicht passenden) Daten zu erwischen ist 
ein Wartungsalptraum. Bei Miniprogrammen wie hier geht das notfalls, 
aber sobald es etwas komplexer wird, baut man sich Bugs ein.
1
#include <stdio.h>
2
#include <stdint.h>
3
4
typedef struct
5
{
6
    uint16_t InputValue;
7
    float FilteredValue;
8
    uint8_t FlagInputValueReadyToProcess;
9
} TFilterStruct;
10
11
enum eFilterName { U1Max, U2Max, U1Avg, U2Avg, NUM_OF_FILTERS};
12
13
TFilterStruct Filters[NUM_OF_FILTERS];
14
15
int main(void)
16
{
17
    //Dummy-mäßig auf irgendwelche Werte setzen:
18
    Filters[U1Max].InputValue = 0xBAD;
19
    Filters[U2Max].InputValue = 0xDEAF;
20
    Filters[U1Avg].InputValue = 0xACDC;
21
    Filters[U2Avg].InputValue = 0xBABE;
22
23
    for (enum eFilterName i = 0; i < NUM_OF_FILTERS; i++)
24
    {
25
        printf("%X\r\n", Filters[i].InputValue);
26
    }
27
28
    printf("Ende.\r\n");
29
    return 0;
30
}

von Tom (Gast)


Lesenswert?

Third E. schrieb:
> Könnte man die for-Schleife zwecks
> Optimierung des Speicherverbrauchs (kleiner µC!) gleich den Pointer
> initialisieren bzw. iterieren?

Das sind Probleme, über die man am Ende nachdenkt, wenn das Projekt 
fertig ist, aber 2 Byte Speicher fehlen und in der geplanten 
Serienproduktion der nächstgrößere uC zu teuer wäre.

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

Tom schrieb:
> for (enum eFilterName i = 0; i < NUM_O

Was ich damit sagen wollte:
Zumindest mit QT Creator wird beim Debuggen der Wert von i als 
Bezeichnung des enums und als Zahl angezeigt, wenn man i als enum 
deklariert. Andere IDEs habe ich nicht ausprobiert.

von L33t 1D107 (Gast)


Lesenswert?

> Man beachte übrigens auch die Dummy-Werte, von oben nach unten gelesen.

Solche Initialisierungen funktionieren nur korrekt mit den Werten 0xDEAD 
0xBEEF 0x1D107 0x7353.

von Marc (Gast)


Lesenswert?

folgende Lösung finde ich elegant:
So kann man jeden Filter direkt ansprechen und für die Display Ausgabe 
ist trotzdem eine Liste vorhanden.
1
#include <stdio.h>
2
#include <conio.h>
3
#include <stdint.h>
4
5
typedef struct
6
{
7
   uint16_t InputValue;
8
   float FilteredValue;
9
   uint8_t FlagInputValueReadyToProcess;
10
} TFilterStruct;
11
12
13
static struct
14
{
15
   TFilterStruct U1Max;
16
   TFilterStruct U2Max;
17
   TFilterStruct U1Avg;
18
   TFilterStruct U2Avg;
19
} Filter = {0};
20
21
22
static const TFilterStruct *FilterList[] = {&Filter.U1Max, &Filter.U2Max, &Filter.U1Avg, &Filter.U2Avg};
23
#define FILTERLIST_SIZE (sizeof(FilterList)/sizeof(FilterList[0]))
24
25
int main(void)
26
{
27
  //Dummy-mäßig auf irgendwelche Werte setzen:
28
  Filter.U1Max.InputValue = 0xBAD;
29
  Filter.U2Max.InputValue = 0xDEAF;
30
  Filter.U1Avg.InputValue = 0xACDC;
31
  Filter.U2Avg.InputValue = 0xBABE;
32
33
  for (int i = 0; i < FILTERLIST_SIZE; i++)
34
  {
35
    printf("%X\r\n", FilterList[i]->InputValue);
36
  }
37
38
  printf("Ende.\r\n");
39
  return 0;
40
}

FilterList kann man auch um Beschreibungstexte ergänzen, nicht 
unpraktisch auf einem Display:
Beispiel:
1
#include <stdio.h>
2
#include <conio.h>
3
#include <stdint.h>
4
5
typedef struct
6
{
7
   uint16_t InputValue;
8
   float FilteredValue;
9
   uint8_t FlagInputValueReadyToProcess;
10
} TFilterStruct;
11
12
13
static struct
14
{
15
   TFilterStruct U1Max;
16
   TFilterStruct U2Max;
17
   TFilterStruct U1Avg;
18
   TFilterStruct U2Avg;
19
} Filter = {0};
20
21
typedef struct 
22
{
23
  const char * pInfotext;
24
  const TFilterStruct *pFilter;
25
} FilterInfoType;
26
27
static const FilterInfoType FilterList[] = 
28
{
29
  {"U1Max", &Filter.U1Max},
30
  {"U2Max", &Filter.U2Max},
31
  {"U1Avg", &Filter.U1Avg},
32
  {"U1Avg", &Filter.U2Avg}
33
};
34
  
35
#define FILTERLIST_SIZE (sizeof(FilterList)/sizeof(FilterList[0]))
36
37
int main(void)
38
{
39
  //Dummy-mäßig auf irgendwelche Werte setzen:
40
  Filter.U1Max.InputValue = 0xBAD;
41
  Filter.U2Max.InputValue = 0xDEAF;
42
  Filter.U1Avg.InputValue = 0xACDC;
43
  Filter.U2Avg.InputValue = 0xBABE;
44
45
  for (int i = 0; i < FILTERLIST_SIZE; i++)
46
  {
47
    printf("%s = %X\r\n", FilterList[i].pInfotext, FilterList[i].pFilter->InputValue);
48
  }
49
50
  printf("Ende.\r\n");
51
  return 0;
52
}

von itzztitz (Gast)


Lesenswert?

für leute mit dynamischem ansatz geht auch ne liste ...
1
struct TFilterStruct{
2
   TFilterStruct     *next;
3
   uint16_t          InputValue;
4
   float             FilteredValue;
5
   uint8_t           FlagInputValueReadyToProcess;
6
};
7
8
TFilterStruct *FilterList;
9
10
void AddToList( ... ){
11
   TFilterStruct *newelement;
12
   newelement = malloc( sizeof( TFilterStruct ) );
13
   ...
14
}
15
16
void DeleteFromList( ... ){
17
18
}
19
20
void foo ( void ){
21
  TFilterStruct *element;
22
  for (element= FilterList ; element!= NULL; element= element->next){
23
     if( element->FlagInputValueReadyToProcess ){
24
         print("%f", element->FilteredValue );           
25
     }
26
  }    
27
}

von itzztitz (Gast)


Lesenswert?

jaaa da fehlt ein "struct"
1
struct TFilterStruct *element;

von Dumdi D. (dumdidum)


Lesenswert?

itzztitz schrieb:
> für leute mit dynamischem ansatz geht auch ne liste ...

Wobei in dem Code ja die Hälfte fehlt...

von A. H. (ah8)


Lesenswert?

Warum willst Du denn überhaupt unbedingt iterieren? Was ist verkehrt an:
1
#include <stdio.h>
2
#include <conio.h>
3
#include <stdint.h>
4
5
typedef struct
6
{
7
   uint16_t InputValue;
8
   float FilteredValue;
9
   uint8_t FlagInputValueReadyToProcess;
10
} TFilterStruct;
11
12
13
static struct
14
{
15
   TFilterStruct U1Max;
16
   TFilterStruct U2Max;
17
   TFilterStruct U1Avg;
18
   TFilterStruct U2Avg;
19
}
20
FilterStructAll = {0};
21
22
void printTFilterStruct(TfilterStruct *tFilterStruct) {
23
  printf("%X\r\n", tFilterStruct->InputValue);
24
}
25
26
int main(void)
27
{
28
   //Dummy-mäßig auf irgendwelche Werte setzen:
29
   FilterStructAll.U1Max.InputValue = 0xBAD;
30
   FilterStructAll.U2Max.InputValue = 0xDEAF;
31
   FilterStructAll.U1Avg.InputValue = 0xACDC;
32
   FilterStructAll.U2Avg.InputValue = 0xBABE;
33
34
   printTFilterStruct(&FilterStructAll.U1Max);
35
   printTFilterStruct(&FilterStructAll.U2Max);
36
   printTFilterStruct(&FilterStructAll.U1Avg);
37
   printTFilterStruct(&FilterStructAll.U2Avg);
38
39
   printf("Ende.\r\n");
40
   getch(); //Auf "Enter" warten.
41
   return 0;
42
}

von A. H. (ah8)


Lesenswert?

Und wenn Du, aus welchen Gründen auch immer, beide Welten brauchst, dann 
vielleicht so (ungetestet!):
1
#include <stdio.h>
2
#include <conio.h>
3
#include <stdint.h>
4
5
typedef struct
6
{
7
   uint16_t InputValue;
8
   float FilteredValue;
9
   uint8_t FlagInputValueReadyToProcess;
10
} TFilterStruct;
11
12
13
static struct
14
{
15
   TFilterStruct U1Max;
16
   TFilterStruct U2Max;
17
   TFilterStruct U1Avg;
18
   TFilterStruct U2Avg;
19
}
20
FilterStructAll = {0};
21
22
static TfilterStruct *FilterArrayAll[] = { 
23
  &FilterStructAll.U1Max,
24
  &FilterStructAll.U2Max,
25
  &FilterStructAll.U1Avg,
26
  &FilterStructAll.U2Avg
27
};
28
29
int main(void)
30
{
31
  static uint16_t init_values[] = { 0xBAD, 0xDEAF, 0xACDC, 0xBABE };
32
33
  assert(sizeof(FilterArrayAll)/sizeof(*FilterArrayAll)==sizeof(init_values)/sizeof(*init_values))
34
  for ( int i=0; i<sizeof(FilterArrayAll)/sizeof(*FilterArrayAll), ++i )
35
     FilterArrayAll[i]->InputValue = init_values[i];
36
37
  for ( int i=0; i<sizeof(FilterArrayAll)/sizeof(*FilterArrayAll), ++i )
38
     printf("%X\r\n", FilterArrayAll[i]->InputValue);
39
40
  printf("Ende.\r\n");
41
  getch(); //Auf "Enter" warten.
42
  return 0;
43
}

: Bearbeitet durch User
von Third E. (third-eye)


Lesenswert?

A. H. schrieb:
> Warum willst Du denn überhaupt unbedingt iterieren?
Der Einwurf ist berechtigt bei gerade mal vier Struct-Elementen. War 
eher eine allgemeine Frage, denn es könnten ja auch sehr viel mehr 
Elemente sein, auf die man iterierbar zugreifen möchte.

von Jasson J. (jasson)


Lesenswert?

Zuerst gebe ich zu, ich habe dein Anliegen nicht ganz durchleuchtet, 
noch alle obigen Beiträge gelesen.

Ich beschäftige mich gerade mit dem Gaphischen Framework "GrLib" von TI 
für die TIVA-C Serie. Das arbeitet mit einer Architektur in C, die es 
erlaubt binäre Bäume aus verschiedenen Struct-Typen aufzubauen, von 
einem Parser durchitterrieren zu lassen und die in den Structs 
befindlichen Daten von einem spezifischen C-File bearbeiten zu lassen.
Das ist von der Idee her ähnlich wie die Grafischen Sachen auch .NET 
oder Qt. Also Buttons, Slider, Checkboxen etc. Das ganze dann mit 
Touchdisplay.

Das ist echt interessant, wie das über defines von Parameterlisten im 
Header und so einer Art sinngemäßen Basisklasse gelöst ist (nennt sich 
"tWidget"). Die Idee ist, das in der Basisklasse u.a. Zeiger auf Parent, 
Next und Child existieren, mit denen ein Parser durch einen Binären Baum 
verschiedener Instanzen und Hierachien itterieren kann. Der Zeiger der 
"Basisklasse" wird dann im C-File Code in einer standadisierten Funktion 
deren Signatur in allen Files gleich ist auf den spezifischen Typ 
umgecastet. Bei dem Funktionsaufruf wird auch ein Argument übergen, was 
die Zielfunktion machen soll. Daüber lassen sich dann wiederum 
spezifische Aktion im jeweiligen C-File realisieren. Erinnert stark an 
den OOP-Interface Gedanken.

Was ich damit beschrieben will ist, dass das die Möglichkeit bietet, 
Daten und "Methoden" auch in C relativ nah an einander zu binden. UND du 
kannst sogar Stucts verschiedener Typen wegen der "Basisklasse" 
hintereinander packen. Also du musst nicht zwingend in Arrays von 
Structs eines bestimmten Typs denken.

Das SW Package wo die GrLib drin ist wäre z.B. TivaWare - wenn du es dir 
tatsächlich ansehen willst. Es gibt sie auch für andere Prozessorfamilen 
von TI wie MSP und AM335 - was dich aber Zwecks Verstehen und Reverse 
Engineering vom FW nicht interessieren braucht.

von Bernd K. (prof7bit)


Lesenswert?

Dumdi D. schrieb:
> Der Code ist nicht sicher. Es ist meiner Meinung nach nicht garantiert,
> dass zwischen den TFilterStructs keine Füllbytes angelegt werden. (Und
> damit springt der Ptr++ zu kurz

Wo sollen die unterschiedlichen Füllbytes denn herkommen? Wenn Ptr von 
selben Typ ist wie die einzelnen Struct-Elemente dann gelten auch die 
selben Alignment-Regeln.

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.