Struct nachträglich erweitern

Hi zusammen,

ich hab wieder mal ne C++ Beginner-Frage:
Kann man bei einem Struct nachträglich (nachdem man schon zahlreiche Werte gespeichert hat) noch ein Feld dazufügen?

Ich hab das versucht, aber sobald ich was am Struct ändere, werden die Daten nicht mehr korrekt ausgelesen.

#include <SD.h> // SD-Kartenleser
File messungenFile;

struct data {
  bool valid;
  uint16_t jahr;
  uint16_t monat;
  uint16_t tag;
  float temperatur;
  //float luftfeuchtigkeit; //NEHMEN WIR AN, DAS SOLL NOCH DAZU...
};

void setup() {

  Serial.begin(115200);

  // Nehmen wir an, ich habe auf die nachfolgende Art bereits zahlreiche Messungen 
  // auf SD-Karte gespeichert (nur ein Beispiel)
  struct data Messung;
  Messung.valid = true;
  Messung.jahr = 2023;
  Messung.monat = 12;
  Messung.tag = 12;
  Messung.temperatur = 25.5;
  messungenFile = SD.open("test.bin", FILE_APPEND);
  if (messungenFile) {
    messungenFile.write((uint8_t *)&Messung, sizeof(Messung));
    messungenFile.close();
  }

  // Und lese die erfolgreich über nachfolgende Art aus:
  messungenFile = SD.open("test.bin", FILE_READ);
  int i = 0;
  if (messungenFile) {
    uint32_t file_size = messungenFile.size();
    uint16_t num_of_reads = file_size / sizeof(Messung);
    while (i < num_of_reads) {
      messungenFile.read((uint8_t *)&Messung, sizeof(Messung));
      Serial.print(Messung.tag);Serial.print(".");Serial.print(Messung.monat);
      Serial.print(".");Serial.print(Messung.jahr);Serial.print(":");Serial.println(Messung.temperatur);
      i++;
    }
    messungenFile.close();
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(10); // this speeds up the simulation
}

Ich geh mal stark davon aus, das hier ist das Problem:

messungenFile.read((uint8_t *)&Messung, sizeof(Messung));

Weil sich quasi die Größe des Structs geändert hat und nicht mehr zur Größe des alten Structs passt.

Aber da gibt es dich bestimmt einen Heimwerker-Hack, mit dem man das Struct ändern kann :upside_down_face:

Danke für eure netten Antworten :slight_smile:

Hmm...
Du möchtest einen Konverter bauen, der von der alten Struktur in die Neue konvertiert.
(ein seit drölfzig Jahren bewährtes Prinzip)

Ich mach mal einen Vorschlag:

struct DATA
{
int one=0;
int two=0;
} data;
struct newData
{
DATA data;
int newValue=0;
}newdata;


Serial.println(newdata.data.one);
Serial.println(newdata.data.two);
Serial.printn(newdata.newValue);

rein pseudo.
Und dann Deine Daten alle auslesen und in eine neue Structur schreiben....

(Vorsicht, ich habe struct auch erst vor kurzem verstanden)

2 Likes

Ich habs fast befürchtet... ok. Dann komm ich da nicht drum rum.

Man kann zwei struct definieren, in die eine (passende) die Daten einlesen,
die andere füllen (mit Werten aus der ersten oder was auch immer),
diese dann in eine andere Datei schreiben.

Achtung: für zwei gleichzeitig offene Dateien hat ein UNO/NANO nicht genug RAM.

Das finde ich grad irgendwie symphatisch :hugs:

1 Like

Da das einlesen über eine Variable geht, kann man Datei 1 schliessen und Datei 2 öffnen und schreiben.
Schliesslich alles entweder über einen Zähler oder auf endOfFile gespielt seh ich da keine Probleme.

Für die Zukunft würde ich noch die Länge und Version der Struct mit in den Struct aufnehmen. Damit ist es dann möglich einen Datensatz zu überspringen, wenn man den nicht verstehen kann.

Ein struct ist kein DBMS!
Wenn überhaupt, dann könnte im File eine Kommentarzeile an den Dateianfang gehören. Alles andere halte ich für überflüssig. Spätestens wenn versucht wird in der Structur noch ein Feld "Version" einzubauen und der Inhalt sowieso nicht mehr gelesen werden kann, führt das zum Absurdum. (Davon abgesheen, dass mindestens ein byte je Datensatz verbraucht wird...)

Mir ist ein Struct mittlerweile auch recht unsympathisch, wird aber dennoch (zumindest was ich so beim Surfen gesehen habe) oft zum Sensor-Daten-Loggen verwendet.

Aber ist halt schon fies, wenn man schon zig tausend Daten gespeichert hat und dann - wenn man ein neues Feld hinzufügen will - gleich alles auf einen neuen Struct umschaufeln muss...das kann von SD-Karte ja quasi Jahre dauern :crazy_face:

Ich hab Dir ja oben einen Vorschlag gamacht.
Und das umschaufeln dauert nicht allzu lange.

Vom Prinzip her kannst Du Dir ja auch C++ Code für den PC schreiben und auf dem Rechner konvertieren.
Das dauert vermutlich nur eine Sekunde.
Du müsstest doch eigentlich Datensicherungen haben, die man verwenden könnte...

#Anekdote
Ich hab auf meinem Ubuntu ein Geany als editor. Der greift auch direkt auf den Ubuntu-integrierten GCC zu.
Du kannst Dir nicht vorstellen, was ich für ein komsichen Gesicht gemacht habe, als der Code (durch irgendeine Tastenkombination ausgelöst) mit einem Mal durchgelaufen ist :slight_smile:

OK, dann bin ich mal zuversichtlich.
Ich mag structs aber trotzdem nicht mehr :laughing:

Ach Du, da kann man sich dran gewöhnen. Vor allem, wenn man da verschachtelte Dinge mit macht...
Im Gegensatz zu einem Array werden nicht alle in size festgelegten Bytes einzeln gespeichert, egal ob benötigt oder nicht. Das spart Platz...
Und dann eben doch der Merksatz: Was zusammengehört, gehört zusammen. :grin:

Irgendwas stört dich, aber du selbst kannst es ja nicht sein, also muss es wohl am Prinzip der Strukturen liegen.

Ganz genau so schauts aus!

Musst ja nicht unbedingt gleich alle umschaufeln - wobei einmal lesen und neu schreiben m.E. das einfachste ist.
In jedem Fall sollte die Datei eine Versionsinformation enthalten, anhand derer Du den Inhalt in "alte", "neue" und später "ganz neue" Struktur unterscheiden kannst.
Lies die alten aus Datei A und schreibe alle neuen in Datei B. Bei Bedarf gibst Du den Daten aus Datei A für die neuen Teile einen sinnvollen Default-Wert (oder einen "nicht benutzt"-Wert).

Ich habe übrigens was Strukturen angeht eine von Deiner abweichende Meinung - das macht aber nix :wink:

3 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.