for each element in stuct ohne array

Moin,

ich möchte in einer Schleife alle Elemente eines Structs durchlaufen:

typedef struct Tuint8_reg{
  String regName;
  uint32_t regAdr;
  uint8_t regVal;
  bool changed;
};

typedef struct TADE7953reg{
  Tuint8_reg SAGCYC;
  Tuint8_reg DISNOLOAD;
  Tuint8_reg LCYCMODE;
};

  TADE7953reg reg = {
    {"SAGCYC",      0x000,      0, false},
    {"DISNOLOAD",   0x001,      0, false},
    {"LCYCMODE",    0x004,      0, false}
  };


//sinngemäß
for each element in reg{
  Tuint8_reg tmp = element;
  Serial.println(tmp.regName):
}

Ich möchte hier exlizit kein array nutzen.
Gibt es denn so etwas in der Art?

Gruß
Pf@nne

Nein. Für sowas bräuchte man Reflection oder in Standard C++ die Boost Library. Mit normalen Mitteln geht es nicht. Bei for each (was in C++11 übrigens gibt, aber nicht so heißt), müssen ja Elemente den gleichen Typ haben geht nicht mit struts

OK, danke für die Antwort!

Ich kann ja mal schildern, was ich vorhabe, bestimmt kann man das auch anders sinnvoll umsetzen.

Ich habe einen MessChip (ADE7953) dieser hat eine Menge Register.
Diese würde ich mit #define angeben:

//8-Bit Registers
#define SAGCYC			  0x000  				    //R/W 0x00 Unsigned Sag line cycles
#define DISNOLOAD		  0x001  				    //R/W 0x00 Unsigned No-load detection disable (see Table 16)
#define LCYCMODE		  0x004  				    //R/W 0x40 Unsigned Line cycle accumulation mode configuration (see Table 17)

Jetzt möchte ich aber fast alle Register auch im Flash des Controllers sichern.
Daher wäre es von Vorteil wenn dies in einem Schleifendurchlauf erfolgen könnte.

Die Sicherung erfolgt über das FS in einen json-File.
Daher möchte ich alle Register durch iterieren.

Hast du eine Idee wie man das am geschiktesten bewerkstelligt?

Gruß
Pf@nne

Nochwas. Range based for loops gehen gar nicht mit structs. Unterschiedliche Typen sind gar nicht das Problem da TADE7953reg ja drei gleiche Variablen hat. Geht aber trotzdem nicht, da die Iteratoren fehlen.

Ein Array aus structs wäre iterierbar. Du kannst die Werte ruhig in structs mit Namen zusammenfassen. Aber für den obersten Container spricht nicht wirklich etwas gegen ein Array.

Also sowas würde gehen:

struct Tuint8_reg
{
  String regName;
  uint32_t regAdr;
  uint8_t regVal;
  bool changed;
};

Tuint8_reg registers[] = 
{
    {"SAGCYC",      0x000,      0, false},
    {"DISNOLOAD",   0x001,      0, false},
    {"LCYCMODE",    0x004,      0, false}
};

void setup() 
{
  Serial.begin(9600);

  for (auto element : registers)
  {
    Serial.println(element.regName);
    Serial.println(element.regAdr);
    Serial.println(element.regVal);
    Serial.println(element.changed);
  }
}

void loop() 
{
}

Genau so, klasse vielen Dank!

Ich möchte die Register und Funktionen des ADE7953 in eigene Files auslagern.
Wie und wo würdest du dieses “Gebilde” am sinnvollsten auslagern?

Ich habe momentan folgenden Sketch:

iterate_struct.ino Sketch

#include "ADE7953.h"
TADE7953 ADE7953;

void setup(){
  Serial.begin(115200); 
  Serial.println("");
  
  ADE7953.init();
}

void loop(){
}

ADE7953.cpp Class ADE7953 Routinen

#include "ADE7953.h"

Treg reg[] ={
    {8, "SAGCYC",      SAGCYC,    33, true,  false},
    {8, "DISNOLOAD",   DISNOLOAD, 44, false, false},
    {8, "LCYCMODE",    LCYCMODE,  55, true,  false}
};

TADE7953::TADE7953(){
}

bool TADE7953::init(){
  for (auto ADEreg : reg){
    Serial.println(ADEreg.BitSize);
    Serial.println(ADEreg.regName);
    Serial.println(ADEreg.regAdr, HEX);
    Serial.println(ADEreg.regVal);
    Serial.println(ADEreg.RW);
    Serial.println(ADEreg.changed);
  }
}

ADE7953.h Class ADE7953 Header

#include "Arduino.h"
#include "ADE7953_REG.h"          //ADE7953 Registers

class TADE7953{
public:
  TADE7953();
  bool init();

/* das geht nicht!?
  Treg classReg[] ={
    {8, "SAGCYC",      0x000, 33, true,  false},
    {8, "DISNOLOAD",   0x001, 44, false, false},
    {8, "LCYCMODE",    0x004, 55, true,  false}
  };*/
     
private:
};

ADE7953_REG.hClass Register Adressen

// ADE7953 config-File struct
typedef struct Treg{
  uint8_t BitSize;
  String regName;
  uint32_t regAdr;
  uint8_t regVal;
  bool RW;
  bool changed;
};

//8-Bit Registers
//      Register Name  Address             R/W Def  Type   Register Description
#define SAGCYC        0x000             //R/W 0x00 Unsigned Sag line cycles
#define DISNOLOAD     0x001             //R/W 0x00 Unsigned No-load detection disable (see Table 16)
#define LCYCMODE      0x004             //R/W 0x40 Unsigned Line cycle accumulation mode configuration (see Table 17)

Jetzt möchte ich gerne das “array of struct” zum Bestandteil meiner ADE7953-Class machen.
Gibt es einen Weg das “array of struct” zur Class hinzuzufügen und gleich zu initialisieren?

Das hier klappt nicht:

class TADE7953{
public:
  TADE7953();
  bool init();

/* das geht nicht!?
  Treg classReg[] ={
    {8, "SAGCYC",      0x000, 33, true,  false},
    {8, "DISNOLOAD",   0x001, 44, false, false},
    {8, "LCYCMODE",    0x004, 55, true,  false}
  };*/
     
private:
};

Hast du da vielleicht auch noch einen Tipp?
Oder würdest du es ganz anders machen?

Gruß
Pf@nne

Iterate_struct.zip (1.41 KB)

Schau dir Initialierungslisten (engl. initializer list) in Zusammenhang mit Konstruktoren an. Das brauchst du auch für andere Sachen.

Es ist auch möglich das Array im Header als extern zu deklarieren und in der .cpp Datei zu definieren. Dann darf das Array aber nicht Teil der Klassen-Definition sein. Das kann hier auch reichen. Das muss ja schließlich nicht unbedingt alles intern in der Klasse sein

OK, schaue ich nochmal rein....

Der Schleifendurchlauf klappt zum Lesen gut,
allerdings kann ich in der Schleife nicht direkt in das struct zurückschreiben.

          int i = 0;
          for (auto element : reg){
            if (element.RW){
              //element.regVal = json[element.regName];  //geht nicht!
              reg[i].regVal = json[element.regName];

            }
            i++;
          }

Ich nehme an, dass mit dem Element nur ein lesender Zeiger weiter geschoben wird.
Daher nutze ich den Umweg über den direkten Zugriff auf das Array.

Geht das auch eleganter?

Gruß
Pf@nne

//element.regVal = json[element.regName];  //geht nicht!

Wieso liest du dir nicht mal eine Anleitung zu "range based for loops" durch? Da wird das erklärt. Für lesenden Zugriff musst du eine Referenz draus machen. Ist auch logisch, dass das mit einem normalen Wert nicht geht.

for (auto &element : reg)

Danke für die Tips!

range based for loops

Das Problem mit dem Lesen ist, dass man erstmal den richtigen Lesestoff finden muss....
Wen die nötigen Suchbegriffe fehlen ist es immer ein wenig schwer...

Gruß
Pf@nne