www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Pointer Problem mit SDCC


Autor: Michael Fluhr (fury)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Michael Fluhr (fury)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Michael Fluhr (fury)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: TheMason (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)
  }

  ...
}

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Michael Fluhr (fury)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Michael Fluhr (fury)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super, das funktioniert mit reentrant.

Vielen vielen Dank Karl Heinz

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: TheMason (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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), ...

Autor: TheMason (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.