Forum: Compiler & IDEs Globales struct definieren und zurücksetzen


von Walter T. (nicolas)


Lesenswert?

Hallo zusamen,
ich habe ein globales Struct, das meine Konfigurationsdaten enthält und 
als globale Variable beim Start initialisiert werden soll.

"Nebenbei" will ich diesen Startzustand zur Laufzeit wiederherstellen 
können. Und zwar ohne, daß ich die Einträge des globalen Structs zweimal 
pflegen will.

Also ungefähr so:
1
// Default-Werte
2
 #define settinginit {\
3
     .z_max_default = Z_MAX_DEFAULT_DEFAULT,\
4
     .t_on_min = T_ON_MIN_DEFAULT,\
5
     .t_off_min = T_OFF_MIN_DEFAULT,\
6
     .duty_cycle_max = DUTY_CYCLE_MAX_DEFAULT,\
7
    // [...]
8
 }
9
10
// Default-Werte für .data:
11
Setting_t gls_setting = settinginit;
12
13
// Default-Werte wiederherstellen
14
void resettodefault(void) 
15
{
16
    gls_setting = edmsettinginit;
17
    return EXIT_SUCCESS;
18
}
"ungefähr so" deshalb, weil es nicht funktioniert (die Zuweisung in der 
Funktion wird mir als "unexpected expression" angemahnt).

Gibt es eine sinnvolle Möglichkeit, das gleiche Struct in einer Funktion 
und im .data zuzuweisen, ohne großartige Verdoppelungen im Quelltext zu 
benötigen?

Viele Grüße
W.T.

: Bearbeitet durch User
von g457 (Gast)


Lesenswert?

> Gibt es eine sinnvolle Möglichkeit, das gleiche Struct in einer Funktion
> und im .data zuzuweisen, ohne großartige Verdoppelungen im Quelltext zu
> benötigen?

Klar, z.B. so:
1
// Default-Werte für .data:
2
Setting_t gls_setting;
3
4
// Default-Werte wiederherstellen
5
void resettodefault(void) 
6
{
7
    gls_setting.z_max_default = Z_MAX_DEFAULT_DEFAULT;
8
    gls_setting.t_on_min      = T_ON_MIN_DEFAULT;
9
    // [..]
10
    //return EXIT_SUCCESS;
11
}
12
13
int main(void)
14
{
15
    resettodefault();
16
    // [..]
17
}

Geht aber nur sinnvoll wenn Du keinen Startup-Code hast, der vor mai() 
auf gls_setting zugreift. Hat dafür den Vorteil, dass man sich keine 
Probleme mit einem Watchdog einhandelt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Lege eine init-Objekt an, das nicht verändert wird. Bei Bedarf wird 
dieses per memcpy in die Zielstruktur kopiert.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Statt
1
    gls_setting = edmsettinginit;

dieses:
1
    gls_setting = (Setting_t)settinginit;

Oder du definierst zwei Variablen vom Typ Setting_t, von denen du eine
mit den Defaultwerten initialisierst. In resettodefault weist du diese
Variable der anderen zu, welche bei Bedarf mit neuen Werten
überschrieben wird.

Johann war schneller :)

Memcpy brauchst du aber nicht unbedingt, da man in C Strukturen auch
direkt zuweisen kann.

: Bearbeitet durch Moderator
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Memcpy brauchst du aber nicht unbedingt, da man in C Strukturen auch
> direkt zuweisen kann.

Stimmt.  Der Compiler baut dann das memcpy selbst ein falls es keine 
günstigere Möglichkeit gibt.

von Walter T. (nicolas)


Lesenswert?

Yalu X. schrieb:
> gls_setting = (Setting_t)settinginit;

Danke, Yalu, das war's, was mir gefehlt hat.

Damit ist die Frage für mich beantwortet und ich bin glücklich. Trotzdem 
noch kurz zu den anderen Posts, deren Ansätze ja auch nicht verkehrt 
sind:

g457 schrieb:
> int main(void)
> {
>     resettodefault();
>     // [..]
> }

Das ist der vorherige Stand, von dem ich weg will, weil mein Startup 
ohnehin schon immer länger wird und dummerweise der Start ungefähr so 
aussieht:
1
int main(void)
2
{
3
    uint_fast8_t status = 0;
4
5
    resettodefault();    // Ueberschreibt gls_setting
6
                         // Nicht wegmachen! Wird gebraucht fuer
7
                         // I2C-Initialisierung
8
9
    status |= i2c_init();
10
    if(status)
11
        goto settings_error;
12
13
    status |= loadconfigfromeeprom(); // Ueberschreibt gls_setting
14
    if (status) 
15
        goto settings_error;
16
17
    [...]
18
19
    settings_error:    
20
21
    if(status) {
22
        resettodefault();            // Ueberschreibt gls_setting
23
    }
24
25
    [...]
26
27
}
Irgendwie ist es mir diese Funktion am Anfang, die eine Variable 
beschreibt, die später auf jeden Fall überschrieben wird, schon lange 
ein Dorn im Auge. Spätestens beim nächsten Aufräumen will ich sie mal 
wieder wegmachen und suche dann nach dem Fehler im I2C-Teil.

Johann L. schrieb:
> Lege eine init-Objekt an, das nicht verändert wird. Bei Bedarf wird
> dieses per memcpy in die Zielstruktur kopiert.

Momentan habe ich massig Flash, aber wenig SRAM frei. Aber ich behalte 
die Methode mal im Hinterkopf.

Vielen Dank und viele Grüße
W.T.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Walter Tarpan schrieb:

> Johann L. schrieb:
>> Lege eine init-Objekt an, das nicht verändert wird. Bei Bedarf wird
>> dieses per memcpy in die Zielstruktur kopiert.
>
> Momentan habe ich massig Flash, aber wenig SRAM frei. Aber ich behalte
> die Methode mal im Hinterkopf.

Du kannst dieses Init-Objekt ja auch in den Flash legen (bzw. im Flash 
belassen).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Walter Tarpan schrieb:
> Momentan habe ich massig Flash, aber wenig SRAM frei. Aber ich behalte
> die Methode mal im Hinterkopf.

Geht dann so und ist ohne explizites memcpy[_P]:
1
typedef struct
2
{
3
    int a, b;
4
} ab_t;
5
6
extern const __flash ab_t ab0;
7
8
void init_ab (ab_t *pab)
9
{
10
    *pab = ab0;
11
}

von Walter T. (nicolas)


Lesenswert?

Was ich (nach einer Pause und einem Kaffee) nicht verstehe:
1
gls_setting = (Setting_t)settinginit;

Ich erzeuge also ein Struct mit
1
// Text, der den Inhalt eines Structs beschreibt.
2
#define settinginit {
3
     .z_max_default = Z_MAX_DEFAULT_DEFAULT,
4
     .t_on_min = T_ON_MIN_DEFAULT,
5
     .t_off_min = T_OFF_MIN_DEFAULT,
6
     .duty_cycle_max = DUTY_CYCLE_MAX_DEFAULT,
7
    // [...]
8
}
9
10
// Text wird in ein Struct gecastet und zugewiesen:
11
Settings_t S = (Settings_t) settinginit;
Also ich erzeuge aus einem Text ein Struct und caste es in ein Struct 
vom Typ "Setting_t". Beide haben dieselben Feldnamen. Aber können bei 
der Zuweisung die Feldnamen überhaupt berücksichtigt werden?

Oder funktioniert das nur korrekt, wenn die Reihenfolge der Feldnamen 
für das im Text beschriebene und das zugewiesene Struct gleich ist und 
auch alle Feldnamen vorhanden sind?

Ich bin mal wieder verwirrt.

Viele Grüße
W.T.

von Stefan E. (sternst)


Lesenswert?

Walter Tarpan schrieb:
> Also ich erzeuge aus einem Text ein Struct und caste es in ein Struct
> vom Typ "Setting_t".

Nein, das ist kein Cast.
Das hier
1
(Settings_t){...}
ist ein "Compound Literal".

Walter Tarpan schrieb:
> Aber können bei
> der Zuweisung die Feldnamen überhaupt berücksichtigt werden?

Das sind keine Zuweisungen, sondern das obige "..." ist die 
Initialisierung des Compound Literals.

Walter Tarpan schrieb:
> Oder funktioniert das nur korrekt, wenn die Reihenfolge der Feldnamen
> für das im Text beschriebene und das zugewiesene Struct gleich ist und
> auch alle Feldnamen vorhanden sind?

Bei der Initialisierung einer Struktur über die Namen spielt die 
Reihenfolge keine Rolle. Auch müssen nicht alle aufgeführt sein 
(ungenannte werden implizit mit 0 initialisiert).

von Walter Tarpan (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Das hier(Settings_t){...}ist ein "Compound Literal".

Hallo Stefan,
danke für die Antwort. Mit diesem Suchwort ließen sich alle Fragen 
klären.

Viele Grüße
W.T.

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.