mikrocontroller.net

Forum: Compiler & IDEs Warning bei fdevopen


Autor: Axel Kieser (axeman)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
WinAVR - 20050214
gcc - 3.4.5
avrlibc - 1.4.2

stdio.h ist included

Beispiel aus AVR-gcc-Tutorial zum Senden von Zeichenketten
Ich bekommen beim kompilieren das Warning:

main.c:54: warning: passing arg 1 of `fdevopen' from incompatible
pointer type
die Zeile lautet
fdevopen(uart_putc,NULL);

Wenn ich - wie im Tutorial-Beispiel - eintrage:
fdevopen(uart_putc,NULL,0);
erhalte ich:
main.c:54: warning: passing arg 1 of `fdevopen' from incompatible
pointer type
main.c:54: error: too many arguments to function `fdevopen'

Was mache ich falsch bzw. wie mache ich es richtig?
Die erste Variante funktioniert im übrigen...

Gruß, Axel

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In die Doku schauen.

Der Prototype von fdevopen sieht so aus:

FILE* fdevopen  (  int(*  put)(char),
                   int(*  get)(void),
                   int opts   __attribute__((unused))
                )

Argument 1 sollte also sein:
Ein Pointer auf eine Funktion. Diese Funktion nimmt einen char
und liefert einen int zurueck.

Wie sieht Deine Funktion (aus dem Tutorial) aus:

int uart_putc(unsigned char c)
{
    while(!(USR & (1 << UDRE))); /* warte, bis UDR bereit */
    UDR = c;                     /* sende Zeichen */
    return 0;
}

Nun. Die Funktion liefert einen int wie gefordert, nimmt
aber einen unsigned char und keinen char. Damit hat diese
Funktion eine andere Signatur als fdevopen sie haben moechte.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz, du hast den Prototypen von avr-libc <= 1.2.x gezeigt, Axel
benutzt offensichtlich eine 1.4.x.

Axel, das wichtigste hast du vergessen uns zu sagen: den Prototypen
(oder die Implementierung) deines uart_putc().  Ich vermute mal, du
hast den zweiten Parameter (FILE *) vergessen, der in der avr-libc 1.4
neu hinzugekommen ist.  Guck mal ins stdiodemo.  Der Sinn dieses
Parameters ist, dass man mittels fdev_set_udata() an den Stream user
data anhängen kann und innerhalb von uart_putc() mittels
fdev_get_udata() über diese verfügen kann.  Damit kann man einerseits
Dinge wie einen Gerätestatus über mehrere Aufrufe pro Stream
abspeichern, andererseits kann man ein und dieselbe backend-Funktion
(also uart_putc() in deinem Falle) für mehr als ein Gerät (z. B. zwei
verschiedene UARTs) benutzen, indem man sie anhand der user data
unterscheidbar macht.

Wenn du diese Funktionalität nicht brauchst, deklarierst du den
zweiten Parameter einfach nur als Dummy, ohne ihn zu benutzen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Karl Heinz, du hast den Prototypen von avr-libc <= 1.2.x gezeigt,
> Axel benutzt offensichtlich eine 1.4.x.

Danke fuer den Hinweis.

Autor: Axel Kieser (axeman)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, ich bin wohl noch viel zu weit weg mit meinen Kenntnissen, um das so
richtig zu verstehen...
so sieht das bei mir aus (das sollte genau dem Beispiel aus dem
gcc-Tutorial entsprechen), damit erfolgt auch eine Ausgabe auf meinem
ATMega32, nur gibt es halt das entsprechende oben beschrieben
fdevopen-Warning:

void USART_Init( void )
{
UCSRB |= (1<<TXEN);//UART TX einschalten
UCSRC |= (1<<URSEL)|(3<<UCSZ0);//Asynchron 8N1

UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);
UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU);
}


int uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE))); /* warten bis Senden moeglich */
    UDR = c;                      /* sende Zeichen */
    return 0;
}

void uart_puts (char *s)
{
    while (*s)
    {   /* so lange *s != '\0' also ungleich dem
"String-Endezeichen" */
        uart_putc(*s);
        s++;
    }
}

int main(void)
{
  USART_Init();

  fdevopen(uart_putc,NULL);
  printf("%s: stdout erfolgreich auf UART umgeleitet\n",
_FUNCTION_);

  sei();

  return 0;
}

Was muss ich in die Klammern von fdevopen schreiben, damit kein warning
mehr kommt?

Gruß, Axel

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK. Du musst lernen wie man sowas loest.
Der Compiler meckert, weil der Prototyp von fdevopen
etwas andere Parameter vorschreibt also Du tatsaechlich
verwendet hast.
Das ist noch kein Beinbruch und das kriegt man raus indem
man ganz einfach mal einen Blick auf den Prototypen wirft.
Den wiederum sieht man entweder in der Doku, oder aber
was meist besser ist direkt im Code. Irgendwiw muss
der Compiler ja den Prototypen sehen und da Du ihn nicht
selbst geschrieben hast, kann er nur ueber ein #include
hineingekommen sein.
Also geht man mal alle #include durch und ueberlegt in welchen
dieser Files der Progtrammierer der Library sinnvollerweise
den Prototyp hineingegeben haben wird. Im vorliegenden Fall
ist 'stdio.h' ein heisser Kandidat.
Ich hab bei mir am Rechner eine etwas aeltere Version davon
(die findet sich bei mir unter c:\winavr\avr\includes) und bei
mir lautet der Prototyp
extern FILE *fdevopen(int (*__put)(char), int (*__get)(void),
                      int __opts);

Aber wie gesagt, ich hab eine etwas ältere Version. Deine
sieht anders aus, wie Jörg weiter oben schon ausgefuehrt hat.

Aus den Ausfuehrungen von Jörg schliesse ich folgendes:
* fdevopen uebergibt man ja 2 Funktionspointer
* diese Funktionspointer sind Zeiger auf Funktionen, die
  jeweils aufgerufen werden, wenn ein Zeichen entweder ausgegeben
  oder eingelesen werden soll.
* damit das aber funktioniert, muessen Deine Funktionen so aussehen
  wie fdevopen sich das so vorstellt. Insbesondere muessen
  die Argumente in Anzahl und Type uebereinstimmen.
* der erste Funktionszeiger im Aufruf von fdevopen ist ein Zeiger
  auf die Ausgabefunktion. In meiner Version ist das eine Funktion
  die einen char annimmt und einen int zurueckliefert. Jetzt hat Jörg
  aber gesagt, dass er diese Funktion mit einem zusaetzlichen
  Parameter, einem File-Pointer ausgestattet hat.
  d.h. Der Protoyp von fdevopen wird wahrscheinlich so aussehen
 (aber pruef das bitte nach!)

  extern FILE *fdevopen(int (*__put)(char, FILE*),
                        int (*__get)(FILE*),
                        int __opts);

* Daraus folgt: damit Deine uart_putc Funktion dazu kompatibel
  ist, muss sie daher der Signatur
              int (*put)(char, FILE*)
  genuegen.

  int uart_putc( unsigned char c, FILE* dummy )
  {
     ....
  }

  Dieser zusätzliche Parameter 'dummy' ist wohl der Stream, auf
  dem die Ausgabe tatsaechlich erfolgen soll. Da Du weist, dass
  die Ausgabe auf den UART gehen soll, ist sein Inhalt fuer Dich
  wahrscheinlich uninteressant und daher hab ich das auch 'dummy'
  genannt. Das muss aber nicht so sein. Warum soll eine einzige
  uart_putc Funktion nicht die Ausgabe auf verschiedene Geräte
  regeln können. Dann braucht man den zusätzlichen Parameter
  um die unterschiedlichen Ausgabeanfoerderungen zum richtigen
  Gerät zuordnen zu können.

Disclaimer: Wie bereits ausgefuehrt verwende ich noch eine ältere
Version der Library. Alles hier geschriebene hab ich aus Jörgs
Info von oben abgeleitet bzw. 'geraten'. Ich denke aber nicht,
daß ich alzuweit daneben liege. Alles beginnt damit, dass Du mal
den Prototypen von fdevopen() in stdio.h ueberpreufts, wie der
tatsächlich aussieht.

Autor: Axel Kieser (axeman)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uff, danke erstmal.
ja, ich muss (und will) lernen, wie man sowas löst... Der Berg ist aber
noch ganz schön hoch.
Deine Mutmaßungen bzgl. fdevopen sind alle richtig; eigentlich hatte
aber schon Dein erster Hinweis gereicht -> aus unsigned char musste
char werden. -> Jedoch ist dann auch das Beispiel im avr-gcc-Tutorial
falsch, dort steht 'int uart_putc(unsigned char c)...

Jetzt läuft es zumindest 'warning'-frei durch; auf zum nächsten
Schritt, die nächste Frage kommt bald.

Gruß, Axel

Autor: (geloescht) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
(Dieser Beitrag wurde geloescht)

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.