Hi,
ist es möglich in C einem Funktionspointer eine fixe Adresse zuzuweisen?
Ich möchte zur Laufzeit den Code in einem reservierten Ram Bereich
ändern und benötige einen Einsprungpunkt. Zum Beispiel die Adresse
0x1234, die sich ebenfalls in einem reservierten Ram Bereich befindet.
1
//So würde ich es bei Variablen machen:
2
int*ptr;
3
ptr=(int*)0x1234;
Aber wie funktioniert es bei ganzen Funktionen?
vielleicht so:
1
//.h Datei
2
voidfunktion(void);
3
4
//.c Datei
5
voidfunktion()
6
{
7
// tu was
8
}
9
10
voidmain()
11
{
12
void(*funktionsPointer)(void)=(void*)0x1234
13
14
funktionsPointer=funktion;
15
//Aufruf von "funktion" über einen Pointer, der fix an der Adresse 0x1234 abgelegt ist
16
(*funktionsPointer)();
17
}
Der Compiler sagt ich kann den Pointer so nicht initialisieren weil sich
"void*" nicht eignet um den Typ "void(*)(void)" zu initialisieren ...
Kann mir jemand sagen ob das generell nicht geht, oder nur ein
Syntaxproblem ist.
Liebe Grüße
Fischle
Hi,
danke nochmals an alle Antwortenden! Dieses Forum ist klasse :)
Nochmals ein kurzer Raport meiner Lösung:
MSP430g2553 auf Launchpad an CCSEv4 (nammi) ....
1
//Im MeinFile.c File bei den globalen Variablen
2
#define IRGENDWASHALT
3
typedefvoid(*fktPtr)(void);
4
externfktPtrptr_MeineFunktion;
5
6
...
7
8
//Im msp430g2553.cmd File direkt unter den Includes
9
#include MeinFile.h
10
ptr_MeineFunktion=0x0200//Erste RAM-Adresse beim MSP430G2553
11
12
...
13
14
//Im MeinFile.h stehen die defines welche zur Aufteilung des
15
//Speicherplatzes verwendet werden
16
#define FKTPTR_START_ADDR (0x0200)
17
#define FKTPTR_END_ADDR (0x020F)
18
#define FKTPTR_LEN (0x0010)//Platz für 8 Pointers
19
//Der Rest vom RAM beginnt dann natuerlich erst bei
20
#define RAM_START_ADDR (0x0210)
21
//Und die Länge von NORAMLRAM_LEN muss um 16Bit gekürzt werden
22
23
24
...
25
26
//Wieder im msp430g2553.cmd File ersetzt man die eine Zeile
Hi,
nächstes Problem ;)
Kann sein, dass W.S. das in seinem Beitrag bereits erklärt hat, ich hab
das BSP aber noch nicht ganz verstanden ...
Ich würde gerne -ebenfalls über den Funktionspointer- eine Funktion
aufrufen, nur diesmal mit Parametern.
Ausgedacht hab ich mir das so:
1
//Probiert hab ich es so wie zuvor nur eben mit Parameter.
//Diesen moechte ich da gern als Zahl eintragen können
22
(*ptr_MeineFunktionMitParameter)(7)
Aber der Compiler mag es nicht ...
Dann dachte ich an ein Call by Reference, also sowas wie:
1
(*ptr_MeineFunktionMitParameter)(&7)
Dafür komm ich wahrscheinlich in die Hölle, aber funktionieren tut es
natürlich auch nicht ...
Weiß jemand Rat? (außer, dass ich noch viel zu lernen hab :D)
Gruß
Fischle
Hi,
...aber in den heißesten Teil der Hölle.
Ist doch eigentlich einfach:
7 ist kein int, sondern eine Compilezeit-Konstante.
Compilezeit-Konstanten belegen keinen Speicherplatz im Sinn von
Variablen, also kann man sie auch nicht referenzieren. Was soll da
rauskommen? D.h. du musst erst einen int-wert mit 7 initialisieren und
dann kannst du mit & auf diesen int-Wert referenzieren.
Und das hier
1
//Funktionsdeklaration
2
voidMeineFunktionMitParameter(int*Parameter)
3
{
4
Parameter++;//irgendwas
5
}
wird auch nicht das tun, was du erwartest. Überleg mal selbst, warum.
>Darf man das in C so machen?
Man darf alles das machen, was der Compiler nicht anmeckert.
Die eigentliche Frage ist "Was willst du machen?"
Zur weiteren Verwirrung:
1
*Parameter++;
2
(*Parameter)++;
3
*(Parameter++);
Alles syntaktisch ok, der Compiler frisst es.
Aber was ist der Unterschied? Und welche der unteren beiden
Schreibweisen entspricht der oberen?
Gruss, Rainer
Das war nur ein Beispiel (mit einem dummen Fehler drin) was in der
Funktion passieren soll ... aber ich lerne immer gerne was dazu :)
Also, hier meine Interpretation:
1
*Parameter++;//Keine Ahnung was hier passieren wird ...
2
//Die Punkt vor Strich Regel kann ich nicht anwenden oder? ;)
3
(*Parameter)++;//Increment des Inhalts vom ptr Parameter
4
*(Parameter++);//Increment des ptr Parameter und dann ein Zugriff ohne Effekt?
wirklich verwenden möchte ich den Parameter nacher so:
1
switch(*Parameter)
2
{
3
case1:
4
foo1();
5
break;
6
case7:
7
foo2();
8
break;
9
//usw...
10
}
Was mich aber auch noch beschäftigt, ist die Frage ob (Codeabschnitt von
vorhin)
Hi, Interpretation der unteren beiden korrekt.
Um festzustellen, was der obere macht, brauchst du die Präzedenzregeln
für unäre Operatoren, gibt's in dem bereits erwähnten K&R-Buch und
bestimmt auch im Netz. Da ++ eine höhere Präzendenz als * hat,
entspricht die Schreibweise ohne Klammern der unteren geklammerten. Aber
denk dir nichts dabei, wenn du die nicht im Kopf hast, ich muss auch
noch nachgucken.
Zu deiner Frage. Natürlich kannst du einen int-Pointer auf eine
bestimmte Adresse zeigen lassen, genauso wie du das mit dem
Funktionspointer gemacht hast. Du musst es nur tun (ich hab die Stelle
zumindest nicht gesehen )
1
int*ptr=(int*)0x208;// Zeigt auf 0x208
2
(*ptr)++;// Zählt die int-variable in 0x208 ff eins hoch
Parameter=0x0208;//hab ich oben nicht extra dazugeschrieben ...
Der Kniff mit dem
1
inti=7;
2
(*ptr_MeineFunktionMitParameter)(&i);
beim Aufruf des Funktionspointers funktioniert zwar, nur passiert da
etwas, dass ich nicht will ...
Die Deklaration
1
inti=7;
passt bei mir nicht ins Konzept, da ich zur Laufzeit meinen Ramspeicher
löschen will und komplett andere Funktionen da hineinkopieren möchte.
(ich weiß, dass man so nicht seine Freitagabende zubringen sollte ...)
Deshalb sind im "Laufzeitdynamischen" (ich nenn das mal so) Code keine
Deklarationen möglich.
Natürlich könnte ich das auch über:
1
//Ein globaler Pointer für die Werteübergabe
2
*Pointer=7;
3
//Aufruf einer Voidfunktion
4
(*MeineFunktion)();
5
6
//und spaetere Verarbeitung des globalen Pointers machen
7
voidMeineFunktion(){
8
//swich case Verarbeitung von *Pointer
9
}
machen, aber
1
(*ptr_MeineFunktion)(7);
wäre natürlich wesentlich schöner und benutzbarer ...
Zum Beispiel wäre das ne Lösung:
1
voidMeineFunktion(intwert){
2
&wert=Pointer;//die Adresse von wert soll 0x0208 sein
3
}
Mal abgesehn davon, dass ich dafür wieder in die C-Hölle komme und es
nich kompiliert wird, könnte ich so zur Laufzeit erstellte Variablen auf
Fixadressen umbiegen und so den Crash vermeiden, wenn ich meinen Ram
lösche und mit anderen Funktionen (und Variablen) beschreibe.
Wie könnte ich das angehen?
>//Zeiger auf ein int, weil ich den übergebenen Wert
6
>//ebenfalls an einer festen Speicheradresse
7
>//zwischengelagert haben möchte.
8
>externint*Parameter;//Ramadresse=0x0208
9
>
10
>//Funktionsdeklaration
11
>voidMeineFunktionMitParameter(int*Parameter)
12
>{
13
>//swich case anweisung mit Inhalt von Parameter
14
>}
15
>
> tatsächlich dafür sorgt, dass die 7 an die Speicheradresse 0x028 gelegt> wird, wenn ich die Funktion mittels
Was willst du wirklich?
Irgendwie hab ich das Gefühl dir ist noch nicht so ganz klar, was da
eigentlich passieren soll.
Was soll jetzt eigentlich über die Funtkionsschnittstelle gehen?
Die Adresse an die der Wert hinsoll, oder der Wert selber.
Wenn zweiteres
1
(*ptr_MeineFunktionMitParameter)(7);
1
voidMeineFunktionMitParameter(intWert)
2
{
3
*Parameter=Wert;
4
}
Der erste Fall, eine Adresse wird übergeben, macht nur dann Sinn, wenn
du auch etwas hast, was eine Adresse hat (oder die Adresse selber). 7
hat keine Adresse. 7 ist eine Konstante und existiert als solches nicht
im Speicher.
Hmm, ich bin mir nicht sicher, ob ich dein Problem richtig verstehe.
Wenn das mit deinem Linkerskript funktioniert, dann hast du sofort, ohne
dass du noch was dazu tun musst, mit der int*-Variablen "Parameter"
einen int-Pointer, der auf 0x208 ff zeigt. Den kannst du sofort
verwenden, als Parameter für deine Funktion, die einen int* erwartet
oder als ganz normale int-Variable per Dereferenzierung: *Parameter=12
D.h. du schreibst dann einfach
Hi,
anscheinend hab ich mal wieder im Kreis gedacht?
Mit der Funktionsdeklaration
1
voidMeineFunktion(intWert)
2
{
3
//verarbeite Wert
4
}
und dem Aufruf
1
(*ptr_MeineFunktion)(7);
tut der Code was er soll und auch beim Austausch des Ramspeicherinhalts
kommt es zu keinem Absturz ...
Ist der Aufruf einer Funktion über ein Funktionspointer sozusagen ein
"Call by Reference"?
Gruß
Fischlein
Fischle schrieb:> Ist der Aufruf einer Funktion über ein Funktionspointer sozusagen ein> "Call by Reference"?
Nein, es macht überhaupt keinen Unterschied, ob du deine Funktion direkt
über MeineFunktion(7) oder ptrMeineFunktion(7) aufrufst. Du Musst es
nicht einmal so komplex schreiben wie du es oben getan hast, d.h.
explizite Dereferenzierung und Klammern kannst du auch weglassen. Das
geht, weil auch "MeinFunktion" selbst aus Compliersicht schon ein Zeiger
auf eine Funktion ist, Dereferenzierung und Aufruf macht der Compiler
automatisch, wenn er Klammern und ggf Funktionsparameter hinter dem
Funktionsnamen findet.
In C werden Aufrufparameter von Funktionen grundsätzlich immer als Kopie
des Aufrufparameters übergeben, also call-by-value. D.h. für die Dauer
der Funktionsausführung arbeitest du mit einer Kopie des übergebenen
Wertes. Aus deiner Konstanten 7 wird während der Funktionsausführung ein
Funktionsargument in Form einer int-Variable (weil du das im
Funktionskopf so festgelegt hast) mit dem Wert 7. Um das Ganze noch
weiter zu komplizieren: Funktionsargumente unterscheiden sich in nichts
von normalen Variablen, außer dem Umstand, dass sie nach jeder
Funktionsausführung wieder gelöscht (=vom Stack geräumt) werden. Damit
kannst du dann auch legal solche Sachen machen wie
1
voidKeks(intparam)
2
{
3
for(;param>0;param--)
4
printf("Param=%d\n",param);
5
}
6
7
intmain(void)
8
{
9
Keks(7);
10
Keks(99);
11
}
Wenn du explizit festlegen willst, dass ein Funktionsparameter wie eine
Konstante behandelt werden soll (in dem Fall als Laufzeitkonstante, denn
der Aufrufmechanismus "Wertkopie" bleibt), dann kannst du das dem
Compiler über das Wort "const" mitteilen, also im obigen Beispiel "const
int param". Probier aus, was der Compiler dann sagt.
Gruss, Rainer