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
voiddummyfkt(void){
3
glcd_putstr_P(PSTR("Ich schreibe also bin ich"));
4
glcd_drawnow();
5
}
6
7
int16_tdummyvar=0;
8
9
const__flashcharTEXT1[]="Hallo";
10
const__flashcharTEXTN[]={'\0'};
11
12
typedefstruct{
13
const__flashchar*text;
14
voidFcn_tfktpointer;
15
int16_t*numvar;
16
}mydata_t;
17
18
const__flashmydata_tDAT_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
voidtest(const__flashmydata_t*(data[])){
27
28
snprintf_P(glstr_Buf,N_TEXTBUF,PSTR("hallo"));
29
glcd_putstr(glstr_Buf);
30
glcd_drawnow();
31
32
voidFcn_tfkt;
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
voidwirdvonmainaufgerufen(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.
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
voidfoo(int*arg)
2
{
3
arg[0]=5;
4
arg[1]=6;
5
}
6
7
intmain()
8
{
9
intval[2];
10
11
foo(val);
12
}
oder mit Array Schreibweise
1
voidfoo(intarg[])
2
{
3
arg[0]=5;
4
arg[1]=6;
5
}
6
7
intmain()
8
{
9
intval[2];
10
11
foo(val);
12
}
Beides ist gleichwertig und bewirkt auch dasselbe.
Aber du willst die Dinge hier nicht mischen. Das hier
1
voidfoo(int*(arg[]))
2
{
3
arg[0]=5;
4
arg[1]=6;
5
}
6
7
intmain()
8
{
9
intval[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__flashmydata_tDAT_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
voidtest(const__flashmydata_tdata[]){
9
10
...
11
}
12
13
voidwirdvonmainaufgerufen(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__flashmydata_tDAT_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.
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__flashmydata_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!
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
voidfoo(intarg[])
2
{
3
arg[0]=5;
4
arg[1]=6;
5
}
6
7
intmain()
8
{
9
intval[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.
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.
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.