Hallo, ich hab mir ein Menü programmiert, das die Funktionen über Pointer aufruft. Jetzt hätte ich beim Aufruf der Funktionen gerne einen Parameter übergeben. SDCC meldet mir D:/Daten/8051/C/Menü.c:120: warning 92: Functions called via pointers must be 'reentrant' to take arguments und kompiliert die Funktionen danach nicht mehr. Kann mir jemand verraten wie ich beim Aufruf von Funktionen über Pointer einen Parameter übergeben ? Im Anhang findet ihr mein komplettes Programm. Gruß Michael
Nochmal ich :-) Im Thread http://www.mikrocontroller.net/forum/read-2-40721.html im Beitrag von Karl Heinz Buchegger (etwa in der Mitte) ist sowas erklärt, aber funktioniert nicht. P.S. Das Struct des Menüs hab ich bereits geändert typedef struct MENU { const unsigned char *MenueText; unsigned char MenueNo; unsigned char NextMenueNo; void (*MenueFunction)(unsigned char); } MENUE_ENTRY;
Nun, du möchtest mit Menue[ArrayPos+MenuePos].MenueFunction(MenuePos); deine Funktion aufrufen. Wie ist MenuFunction deklariert: typedef struct MENU { const unsigned char *MenueText; unsigned char MenueNo; unsigned char NextMenueNo; void (*MenueFunction)( void ); } MENUE_ENTRY; Da steht: Menufunction ist ein Zeiger auf eine Funktion die nichts zurückliefert (das erste void) und keine Argumente nimmt (das zweite void). Wenn du also der Funktion Argumente geben willst, dann musst du das in der Deklaration des Funktionszeigers auch vereinbaren: void (*MenueFunction)( unsigned char ); Jetzt ist MenuFunction ein Zeiger auf eine Funktion die als erstes Argument einen unsigned char nimmt. Natürlich müssen jetzt auch alle Funktionen die du an so einem Funktionszeiger binden willst auch tatsächlich einen unsigned char annehmen.
Hallo Karl Heinz, genau das hab ich in meinem 2.Post beschrieben, aber die Fehlermeldung bleibt dieselbe. Das merkwürdige ist, das die gleiche Zeile bemängelt wird. Es funktioniert auch, wenn ich einen Zeiger benutze der nicht in einem Struct definiert ist. Ich suche also weiter, wie richtig auf Elemente eines Structs zugegriffen wird.
Das stimmt an und für sich alles, da das Standard-C ist. Die Fehlermeldung allerdings deutet darauf hin, dass das ein compilerspezifisches Problem ist. Der Ausdruck 'reentrant' ist im C-Standard nicht definiert (auch wenn wir alle wissen was damit gemeint ist). Da wirst du also im Compiler-Handbuch suchen muessen, was dem Compiler da nicht passt.
ich kenn mich zwar mit dem sdcc nicht so aus, aber hast du mal folgendes probiert (sollte eigentlich mit jedem compiler möglich sein) : typedef void (FKT_ZEIG) (char cParameter1); void test (char cPar1) { ... } FKT_ZEIG *func1 = (FKT_ZEIG *) &test; void main (void) { char cP = 10; ... if (func1 != NULL) { func1 (cP) } ... }
Ich vermite mal, dass es da noch irgendeine 'Dekoration' für die Funktion gibt, mit dem man dem Compiler mitteilt, dass die Funktion tatsächlich reentrant ist.
> Es funktioniert auch, wenn ich einen Zeiger benutze der nicht in > einem Struct definiert ist. Das ist interessant. Versuch mal: (Menue[ArrayPos+MenuePos].MenueFunction)(MenuePos); oder (*(Menue[ArrayPos+MenuePos].MenueFunction))(MenuePos); Sollte eigentlich keinen Unterschied machen, wenn ich die Precedence Regeln noch richtig im Kopf habe, aber es soll ja auch schon Compilerfehler gegeben haben.
@TheMason unsigned int foo1( int Arg1 ) { return (int)( Arg1 + 0.5 ); } void main(void) { unsigned int (*MyFunc)( int ); MyFunc = foo1; i = (*MyFunc)( 4 ); /* Aufruf der Funktion ueber den Pointer */ } Das funktioniert, wobei Das Ergebnis natürlich Quatsch ist. @Karl Heinz Das Klammern reicht nicht, aber ich habe auch den Verdacht, das es am Compiler liegt. Bei Gelegenheit werde ich das mal Visual C testen.
Kannst du dir sparen. In Visual C und allen anderen C-Compilern auf denen ich bisher gearbeitet habe funktioniert das klaglos. Muss es auch. Entspricht so den C-Regeln.
Auf einer Website (google: SDCC reentrant) habe ich folgenden Satz gefunden: <Zitat> Avoid calling functions from within an ISR. If you must do this, declare the function as reentrant (see SDCC manual) which allocates all local variables in the function on the stack instead of in RAM. </Zitat> besonders der letzte Satzteil "which allocates all local variables in the function on the stack instead of in RAM" lässt bei mir die Alarmglocken klingen. Auf jeden Fall: Das ist irgendetwas SDCC spezifisches. Aus mehreren anderen Websites habe ich mal folgendes abgeleitet: typedef struct MENU { const unsigned char *MenueText; unsigned char MenueNo; unsigned char NextMenueNo; void (*MenueFunction)(unsigned char) reentrant; } MENUE_ENTRY; Und dann natürlich noch jede Funktion mit dem Zusatz 'reentrant' ausstatten.
Etliche 8bit Microcontroller tun sich mit Daten auf dem Stack erheblich schwerer als mit statisch adressierten Daten. Vor allem wenn die Architektur zu einem Zeitpunkt entstand, als C in diesem Sektor noch nicht verbreitet war (8051,PIC). Und so ist es bei solchen Compilern üblich, bis auf Widerruf lokale Daten statisch zu adressieren. Macht Keil auch nicht anders.
also ist das verhalten von funktionszeigern beim sdcc nicht so einfach wie ich es unter standard c gewohnt bin. gibt es damit eigentlich probleme bei anderen compilern (z.b. mspgcc/armgcc usw ...) ?! würde mich mal interessieren wenn ich mal was mit beispielsweise eclipse mache ... (ob es da auch ähnlich problematisch ist) gruß rene
Eclipse ist kein Compiler. GCC für ARM,AVR,MSP430 arbeitet normal, eine spezielle Kennzeichnung derartiger Funktionen ist nicht erforderlich. Zilog Z8 kann zwar mit Stack-Daten umgehen, der Compiler benutzt in Standardeinstellung jedoch statische Adressierung. Compiler für Microcontroller sind meistens mit architekturspezifischen Eigentümlichheiten gesegnet. Getrennte Adressräume für Code und Daten erschweren das Leben (8051,AVR,PIC), Interrupt-Routinen müssen speziell behandelt werden (alle), komprimierter Code fordert Tribut (ARM-Thumb), ROM-Banking kann u.U. eine Reorganisation des Quellcodes erfordern (PIC), ...
@a.k. sorry, meinte natürlich nicht eclipse als solches sondern mit den jeweilgen plugins für verschiedene mikrocontroller unter eclipse. mit den wüsten adressräumen beim 8051 habe ich schon bekanntschaft gemacht. beim msp430 hatte ich bis jetzt keine probleme (speziell mit funktionszeigern, da ich oftmals exzessiven gebrauch davon mache :-) deswegen hab ich auch meinen (überflüssigen) senf dazugegeben, weil mich mal interessieren würde bei welchen prozessoren funktionszeiger probleme machen können. gruß rene
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.