Initialisierung großer structs mit vielen Nullen

Gast #2640916
Hallo,

bei meinem Projekt kommt es auf jedes Byte an. Beim Optimieren habe ich 
festgestellt, dass die Initialisierung von Variablen eigentlich besser 
laufen könnte.
Ich habe z.B. einen großen struct bzw. Array davon (mit Beispielwerten):
1
typedef union {
2
  uint8_t Index[5];
3
  struct {
4
    uint8_t A, B, C, D, E;
5
  } Name;
6
} tFlex;
7

8
typedef struct {
9
  int8_t Alpha, Beta;
10
  tFlex flex;
11
} tData;
12

13
tData Data[COUNT_DATA] = {
14
  { 7,  1, {{ 23,  42,   1,   2,   3}}},
15
  { 2,  4, {{ 47,  11,   0,   0,   7}}},
16
  {47, 87, {{  0,   8,  15,   0,   0}}},
17
  { 9, 73, {{  3,   1,   4,   1,   5}}},
18
  { 5, 10, {{  1,   1,   2,   3,   5}}},
19
  { 2, 11, {{ 90,  60,  90,   0, 190}}},
20
  { 1,  0, {{  0,   0,   0,   0,   0}}},
21
  { 1,  0, {{  0,   0,   0,   0,   0}}},
22
  { 1,  0, {{  0,   0,   0,   0,   0}}},
23
  { 1,  0, {{  0,   0,   0,   0,   0}}},
24
  { 1,  0, {{  0,   0,   0,   0,   0}}},
25
  { 1,  0, {{  0,   0,   0,   0,   0}}},
26
  { 1,  0, {{  0,   0,   0,   0,   0}}},
27
  { 1,  0, {{  0,   0,   0,   0,   0}}},
28
  { 1,  0, {{  0,   0,   0,   0,   0}}},
29
  { 1,  0, {{  0,   0,   0,   0,   0}}},
30
  { 1,  0, {{  0,   0,   0,   0,   0}}},
31
// ...diese "leeren" (man beachte die 1 an Stelle 1)
32
//   Zeilen wiederholen sich bis zum Ende des Arrays...
33
}

Dieses Array befindet sich im RAM und im EEPROM. Die o.g. Werte sind der 
Default, für den Fall, dass die Werte im EEPROM ungültig sind oder falls 
man einen Reset der Werte auf den Default braucht.

Mein Gedanke war nun folgender: Da im Default nur einige Zeilen Werte 
enthalten, müsste sich doch durch die Art und Weise des Init eine Menge 
Platz sparen lassen. Kann man irgendwie "in einem Rutsch" einen Struct 
aus dem ROM ins RAM kopieren?

Ich habe es so probiert, aber das frisst auch ziemlich viel Speicher:
Erst die Ganze Geschichte als noinit (im Gegensatz zu oben):
1
tData Data[COUNT_DATA] __attribute__((section(".noinit")));

Dann die entscheidenden ersten Zeilen ins ROM:
1
const tData InitData[7] PROGMEM = {
2
  { 7,  1, {{ 23,  42,   1,   2,   3}}},
3
  { 2,  4, {{ 47,  11,   0,   0,   7}}},
4
  {47, 87, {{  0,   8,  15,   0,   0}}},
5
  { 9, 73, {{  3,   1,   4,   1,   5}}},
6
  { 5, 10, {{  1,   1,   2,   3,   5}}},
7
  { 2, 11, {{ 90,  60,  90,   0, 190}}},
8
  { 1,  0, {{  0,   0,   0,   0,   0}}}
9
}

Und nun:
1
void copydata(const tData *source, tData *dest) {
2
  dest->Alpha = pgm_read_byte(&source->Alpha);
3
  dest->Beta = pgm_read_byte(&source->Beta);
4
  uint8_t i;
5
  for (i = 0; i < 5; i++) dest->Flex.Index[i] = pgm_read_byte(&source->Flex.Index[i]);
6
}
7

8
uint8_t i;
9
for (i = 0; i < 6; i++) copydata(&InitData[i], &Data[i]);
10
for (i = 6; i < COUNT_DATA; i++) copydata(&InitData[6], &Data[i]);

Ich empfinde den Zugriff auf jedes Element mit pgm_read_byte als sehr 
umständlich. Geht das nicht irgendwie in einem Rutsch bzw. mit einer 
einzigen Schleife?
Gast
Danke! Weiß auch nicht, wie mir memcpy_P entgehen konnte. Damit klappt's 
gut und es spart mir jetzt insgesamt im fertigen Programm ca. 250 Bytes, 
was natürlich ein kleiner Jackpot ist.
1
uint8_t i;
2
memcpy_P(&Data[0], &InitData[0], COUNT_INITDATA * sizeof(tData));
3
for (i = COUNT_INITDATA; i < COUNT_DATA; i++) memcpy_P(&Data[i], &InitData[COUNT_INITDATA-1], sizeof(tData));

Vielleicht gibt's ja noch revolutionär andere Ideen zu dem Thema...
Gast
Hätte ja sein können, dass das auch ein Feature ist, das ich übersehen 
habe. ;)
Aber mal ehrlich, spart das wirklich Platz oder ist das nur eine etwas 
eleganter aussehende Konstruktion? Ich meine, intern kocht der GCC auch 
nur mit Wasser. Und neuere Versionen neigen im Allgemeinen doch eher 
dazu, größeren Code zu erzeugen.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.