Forum: Compiler & IDEs AVR-GCC: const __flash struct mydata_t *[4]


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
ich habe ein großes Struct, daß mir empfindlich viel SRAM wegnimmt. 
Deswegen will ich es in den Flash verlegen. Dummerweise komme ich so 
langsam mit den Datentypen ins Schleudern. Zum Testen habe ich ein 
kleines Mock-up gemacht:
1
// Struct und seine Inhalte
2
void dummyfkt(void) {
3
  glcd_putstr_P(PSTR("Ich schreibe also bin ich"));
4
  glcd_drawnow();  
5
}
6
7
int16_t dummyvar = 0;  
8
9
const __flash char TEXT1[] = "Hallo";
10
const __flash char TEXTN[] = {'\0'};
11
12
typedef struct {
13
  const __flash char *text;
14
  voidFcn_t fktpointer; 
15
  int16_t *numvar;
16
} mydata_t;  
17
18
 const __flash mydata_t DAT_TESTS[] = {
19
   {TEXT1,dummyfkt,&dummyvar},
20
   {TEXT1,dummyfkt,&dummyvar},
21
   {TEXT1,dummyfkt,&dummyvar},
22
   {TEXTN,NULL,NULL}, // Nullzeile markiert Ende des structs
23
 };
24
25
// Test
26
void test(const __flash mydata_t *(data[])) {
27
 
28
  snprintf_P(glstr_Buf,N_TEXTBUF,PSTR("hallo"));
29
  glcd_putstr(glstr_Buf);
30
  glcd_drawnow();
31
32
  voidFcn_t fkt;
33
  fkt = data[1]->fktpointer;
34
  fkt(); // Geht schief
35
36
  snprintf_P(glstr_Buf,N_TEXTBUF,&(data[1]->text)); // Geht auch schief
37
  glcd_putstr(glstr_Buf);
38
  glcd_drawnow();
39
}
40
41
// Aufruf
42
void wirdvonmainaufgerufen(void) {
43
  test(&DAT_TESTS);
44
}
Wie man sieht, enthält das struct Funktionszeiger, Zeiger auf globale 
Variablen und Zeiger auf Text im Flash. So ganz sicher bin ich mir noch 
gar nicht, welche Teile sich davon überhaupt im Flash speichern lassen.

Und ich bin gerade völlig ratlos: Wie dereferenziert man richtig einen 
Zeiger in einem Struct im Flash auf einen String im Flash?

Viele Grüße
W.T.

von Karl H. (kbuchegg)


Lesenswert?

Walter Tarpan schrieb:

> void test(const __flash mydata_t *(data[])) {

Die Funktion kriegt ein Array von Pointern?
Bist du dir da sicher, dass du das willst?

Hmm.
Du verwendest es hier
1
fkt = data[1]->fktpointer;

fast richtig (wir fangen bei 0 zu zählen an und nicht bei 1). Ich denke 
aber trotzdem nicht, dass das das ist, was du eigentlich wolltest. Und 
zwar wegen dem hier
1
  test(&DAT_TESTS);


Grundsätzlich.
Du kannst ein Array auf 2 verschiedenen Schreibweisen übergeben.

Entweder in Pointer-Syntax
1
void foo( int *arg )
2
{
3
  arg[0] = 5;
4
  arg[1] = 6;
5
}
6
7
int main()
8
{
9
  int val[2];
10
11
  foo( val );
12
}

oder mit Array Schreibweise
1
void foo( int arg[] )
2
{
3
  arg[0] = 5;
4
  arg[1] = 6;
5
}
6
7
int main()
8
{
9
  int val[2];
10
11
  foo( val );
12
}


Beides ist gleichwertig und bewirkt auch dasselbe.
Aber du willst die Dinge hier nicht mischen. Das hier
1
void foo( int *(arg[]) )
2
{
3
  arg[0] = 5;
4
  arg[1] = 6;
5
}
6
7
int main()
8
{
9
  int val[2];
10
11
  foo( &val );
12
}

macht etas komplett anders und wird auch in einem komplett anderen Fall 
benötigt. zb dann, wenn du mehrere Arrays hast, deren Adressen du in 
einem weiteren Array einträgst und du dann dieses Pointer Array an eine 
Funktion übergibst.

Ich denke nicht, dass du das hier willst.

Also: nicht so kompliziert
1
const __flash mydata_t DAT_TESTS[] = {
2
   {TEXT1,dummyfkt,&dummyvar},
3
   {TEXT1,dummyfkt,&dummyvar},
4
   {TEXT1,dummyfkt,&dummyvar},
5
   {TEXTN,NULL,NULL}, // Nullzeile markiert Ende des structs
6
 };
7
8
void test(const __flash mydata_t data[]) {
9
10
...
11
}
12
13
void wirdvonmainaufgerufen(void) {
14
  test( DAT_TESTS );
15
}

dann klappt es auch mit dem Zugriff.
Und da du in der Funktion ein Array von mydata_t Objekten hast, ist ein 
Objekt von diesem Array zum Beispiel der
1
   data[1]
Da es sich dabei um ein komplettes mydata_t Objekt handelt (es ist ja 
ein Objekt aus dem ganzen Array), wird ein Member von diesem Objekt, zum 
Beispiel der fktpointer, mit der ganz normalen . Notation angesprochen. 
Der fktpointer vom data[1] ist daher
1
   data[1].fktpointer

Das wäre dann der hier
1
const __flash mydata_t DAT_TESTS[] = {
2
   {TEXT1,dummyfkt,&dummyvar},
3
   {TEXT1,dummyfkt,&dummyvar},                <-------------
4
   {TEXT1,dummyfkt,&dummyvar},
5
   {TEXTN,NULL,NULL}, // Nullzeile markiert Ende des structs
6
 };


> Wie man sieht, enthält das struct Funktionszeiger, Zeiger auf globale
> Variablen und Zeiger auf Text im Flash. So ganz sicher bin ich mir noch
> gar nicht, welche Teile sich davon überhaupt im Flash speichern lassen.

passt schon.
Das sind alles Zeiger. Solange sie nicht auf irgendwas anderes zeigen 
können müssen, ist das ok.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Hallo Karl-Heinz,
wie schaffst Du das nur, so schnell eine Übersicht in mein 
undurchsichtiges verzeifeltes herumprobieren zu bringen und dann auch 
noch die Geduld zu haben, das wirklich zu machen?

Der Compiler warnt mich zwar bei
1
test(&DAT_TESTS);
 mit "passing argument 1 of 'test' from incompatible pointer type", aber 
das wird jetzt gnadenlos mit
1
test( (const __flash mydata_t *) &DAT_TESTS);
unterdrückt.

Vielen Dank für Deine Hilfe!
W.T.

EDIT: Wahnsinn! Ich habe gerade fast 500 bytes Stack geschenkt bekommen! 
Und nochmals Danke!

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Walter Tarpan schrieb:

>
1
> test( (const __flash mydata_t *) &DAT_TESTS);
2
>

Das & da drinnen ist hoffentlich nur ein Tippfehler hier im Forum.
Das gehört da nicht hin

Falls nicht:
Und wenn du es dann weg gibst, dann kannst du auch den Cast wieder raus 
nehmen.

-> Du hast auf die Fehlermeldung falsch ragiert. Der Cast war nicht die 
Lösung, um auf das Problem zu reagieren, das der Compiler angemerkt hat.


Siehe hier
1
void foo( int arg[] )
2
{
3
  arg[0] = 5;
4
  arg[1] = 6;
5
}
6
7
int main()
8
{
9
  int val[2];
10
11
  foo( val );
12
}

an dieser Stelle, beim Funktionsaufruf, fungiert der Name des Arrays 
bereits als seine Adresse im Speicher. Perfekt passend, um in der 
Funktion in einer Pointervariablen (die hier durch die Array Syntax 
verschleiert wurde) gespeichert zu werden. Da braucht es kein &. Ganz im 
Gegenteil: es ist definitiv falsch, auch wenn manche Compiler das 
stillschweigend korrigieren.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> -> Du hast auf die Fehlermeldung falsch ragiert. Der Cast war nicht die
> Lösung, um auf das Problem zu reagieren, das der Compiler angemerkt hat.

Wenn es um Pointer geht, dann ist eigentlich meistens ein Cast NICHT die 
Lösung um auf eine Datentypunverträglichkeit (die jetzt nicht auf 
volatile oder const zurückzuführen ist) zu reagieren. Wenn dir der 
Compiler eine Datentypunverträglichkeit im Zusammenhang mit Pointern 
meldet, dann ist das ein ernst zu nehmendes Problem - den Compiler mit 
einem Cast ruhig zu stellen ist in 99% aller Fälle die meistens falsche 
Lösung. Es ist wie das Überkleben der Öl-Warnung im Auto mit Klebeband. 
Das die Lampe leuchtet siehst du nicht mehr. Aber deswegen hat sich das 
Problem im Ölkreislauf ja nicht gelöst.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Du hast Recht! Das habe ich in der Euphorie, daß in der Funktion, die 
das große struct bearbeitet, nichts außer dem Header geändert werden 
muß, übersehen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

1
typedef struct {
2
  const __flash char *text;
3
  voidFcn_t fktpointer; 
4
  int16_t *numvar;
5
} mydata_t;

Aber so ein "Gemisch" geht nicht, oder kann ich was dazu lernen? 
Manchmal wär's ganz praktisch.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Warum nicht? Es sind alles Zeiger auf zur globale Variablen, also zur 
Kompilier-/Linkerzeit bekannt.

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.