Iteration über Struct

OP #4560391
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
}
Gast #4560434
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
}
Gast #4560441
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.
Gast #4560934
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
}
Gast #4561077
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
}
#4561154
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
}
#4561184
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
}
#4563080
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.
#4563205
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren