Forum: Compiler & IDEs Printf-Lib im GCC-Tutorial


von Marian (Gast)


Lesenswert?

Hallo Softwarefreunde :)

Ich habe ein kleines Problem mit dem GCC-Tutorial. Es geht um den
Bereich "Uart-String senden".
Dort gibt es mehrere Möglichkeiten dies zu realisieren. Den
"normalen" Weg mit uart_puts habe ich verstanden und es funktioniert
auch bei mir. Nun möchte ich die Printf- Variante testen.
Dort steht folgendes dazu:

/* verwenden der printf-lib: */
int main(void)
{
    /* initialisieren der UART */
    uart_init();

    /* stream öffnen */
    fdevopen(uart_putc, NULL, 0);

    /* printf... */
    printf("%s: stdout erfolgreich auf UART umgeleitet\n",
_FUNCTION_);

    /* exit... */
    return 0;
}
Nun zu meinem Problem. Mein AVR-Studio meckert rum, dass es diese
Library nicht finden kann (die printf-Lib). Im AVR-Ordner konnte ich
sie selbst auch nicht finden. Ich brauche sie aber, um die Funktionen
fdevopen und printf nutzen zu können. Wie kann ich diese Library nun in
meinen Code einbinden?

Hoffe ihr habt mein Problem verstanden.

Ich danke euch schon einmal für eure Hilfe!

Gruß Marian

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

printf() ist Bestandteil der normalen C-Bibliothek.

Wenn dein AVR-Studio sich über irgendwas beklagt, solltest du
bitte die Fehlermeldung posten.

(Es gibt separate Bibliotheken mit einer aufgerüsteten Version
von printf() für Gleitkomma-Ausgaben und mit einer abgerüsteten,
um ein bisschen ROM zu sparen, aber die sind hier erstmal nicht
relevant.)

von Marian (Gast)


Lesenswert?

Hm...das dachte ich mir auch schon.
Is mir schon ganz schön peinlich, ich habe vergessen, die stdio.h
einzubinden. Nun erkennt er die Befehle logischerweise. Bin halt noch
ein Anfänger :(. Jedenfalls funktioniert es jetzt.
Jetzt habe ich aber eine andere Frage.
Was macht _FUNCTION_ in der printf-Anweisung? Wenn ich es weglasse,
wird nichts mehr gesendet. Das NULL,0 in der fdevopen habe ich auch
nicht verstanden.

Kannst du mir das bitte mal erklären?
Es gibt leider keinerlei Erläuterung dazu.

Danke und Gruß

Marian

von Fritz G. (fritzg)


Lesenswert?

_FUNCTION_ wird durch den Funktionsnamen ersetzt, in der du grad
bist.

In deinem Fall also mit "main".

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Was macht _FUNCTION_ in der printf-Anweisung?

_FUNCTION_ ist eine GCC-Erweiterung zum Standard.  Dieser
Präprozessor-Makro wird automatisch zu einem String-Literal mit dem
Namen der aktuellen Funktion ("main" also in deinem Falle)
erweitert,
sodass man ihn als Text benutzen kann.  Vom Standard offiziell
vorgesehen sind _FILE__ und __LINE_ für den Dateinamen und die
Zeilennummer, an der sie sich gerade befinden.

Du kannst das also auch erweitern zu:

printf("Das ist Datei %s, Zeile %d in Funktion %s\n",
       _FILE_, _LINE_, _FUNCTION_);

> Das NULL,0 in der fdevopen habe ich auch
> nicht verstanden.

Das NULL (ein Makro, der einen Null-Zeiger kennzeichnet) steht als
Platzhalter dafür, dass du keine Eingabefunktion mit übergeben hast,
sondern nur eine für die Ausgabe.

Die abschließende 0 steht für einen dritten Parameter, der für
Erweiterungen der Funktionalität vorgesehen war, aber nie benutzt
worden ist.  Da wir in avr-libc 1.4 das API ohnehin umgebaut haben,
haben wir den dritten Parameter dort auch gestrichen.

von Marian (Gast)


Lesenswert?

OK danke für die nette Erläuterung.

von Marian (Gast)


Lesenswert?

Nochmals Danke Jörg!
Ich habe gerade beim suchen nach einer lösung für ein anderes Problem,
den Thread gefunden, wo du das ja schonmal einem Anfänger erklärt hast.
Is schon witzig, daß man das findet wonach man gar nicht sucht bzw. wenn
man was anderes sucht:).

von Marian (Gast)


Lesenswert?

Hallo,

ich habe nochmal eine Frage zu dem printf Befehl. Ich würde damit gerne
eine 32 bit integer Zahl als Hex ausgeben. Leider funktioniert das nicht
so wie ich es mir dachte. Wenn ich eine Variable unsigned int z
übergebe, hat diese (logischerweise???) nur 16 bit. Ich habe nun
versucht, eine unsigned long z zu übergeben(ich dachte damit habe ich
32 bit) aber damit kommt der printf Befehl nicht klar. Er möchte halt
einen Integer-Wert haben, da ich ja in Hex umwandle(mit %08x). Nun habe
ich die Doku durch und die ganzen Makros gefunden (Mit denen man die
Datentypen konvergieren kann z.b. Prix8, Prix32 usw.). Leider mag mein
AVR-Studio diese Makros nicht und ich komme jetzt nicht mehr weiter.

Kann mir jemand helfen?
Hier Ausschnitte aus meinem Code :

#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef unsigned long int   uint32_t;
#define  PRIx32   "lx";

int main(void)
{
  /* initialisieren der UART */
    UART_Init();
  uint32_t z=0;

    for(;;)
    {
      /* stream öffnen */
      fdevopen(uart_putc, NULL,0);

      /* printf... */
      printf("S"lx" ms \n\r",z);
    srand(1);
    int zufall = rand() % 500;
    z=z+zufall;
    }
  }
Diese Fehlermeldung erscheint dann:
Timestamp.c:51: warning: passing arg 1 of `fdevopen' from incompatible
pointer type
Timestamp.c:54: error: parse error before "lx"
make: *** [Timestamp.o] Error 1
Build failed with 1 errors and 1 warnings...

Langsam verzweifel ich an der 32 bit Ausgabe. Wenn ich es normal mit
%08x ausgebe, gibt er mir immer nur 16 bit HEX aus.

von Daniel (x2) (Gast)


Lesenswert?

Ich würde dir gern helfen, jedoch habe ich das gleiche Problem!

Sorry...:(

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Timestamp.c:54: error: parse error before "lx"

Wolltest du eventuell

printf("S%lx" ms \n\r",z);

schreiben?  Das wäre dann richtig gewesen.

> Timestamp.c:51: warning: passing arg 1 of `fdevopen' from
incompatible pointer type

Du solltest dein uart_putc() kompatibel zu den Erwartungen
von fdevopen() machen...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Quark.  Natürlich:

printf("S%lx ms \n\r",z);

von Marian (Gast)


Lesenswert?

DAnke Jörg, du warst schon so oft mein Retter ;).

Anscheinend habe ich wohl die letzte Variant nicht ausprobiert, alle
anderen bzgl." habe ich eigentlich getestet. C is schon komisch :).
Das mit fdevopen weiß ich auch, habe auch schon viel Beiträge darüber
gefunden aber irgendwie hauen eure Lösungsvorschläge nicht hin. Wenn
ich meine uart_putc Routine anpasse, freut sich fdevopen aber dann
meckert AVR-Studio mit der uart Funktion rum.

Das kommt wenn ich " int uart_putc(char *s) " nehme:
Timestamp.c:28: warning: control reaches end of non-void function

Das kommt wenn ich " void uart_putc(char*s) " nehme:
Timestamp.c:50: warning: passing arg 1 of `fdevopen' from incompatible
pointer type

Und wenn ich noch FILE* dummy (wie in dem anderen Beitrag erwähnt)
eintrage, dann will er gar nicht mehr.

ihr habt das ja wikrlich nett erklärt in dem anderen Beitrag aber ich
steige dda noch nicht so ganz hinter...sorry.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Timestamp.c:28: warning: control reaches end of non-void function

Du sollst ja auch eine 0 zurückgeben, wenn dein uart_putc()
erfolgreich war.

RTFM gewissermaßen.  Es gibt auch ausreichend Beispiele in der
Doku...

> Und wenn ich noch FILE* dummy (wie in dem anderen Beitrag erwähnt)
> eintrage, dann will er gar nicht mehr.

Das ist ein avr-libc 1.4 Feature.  Du hast offenbar noch eine 1.2er
Version.

von Marian (Gast)


Lesenswert?

Danke nochmals, ich werde jetzt mit den ganzen Fragen aufhören aber ich
finde, diese Douks sind echt s..... geschrieben.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Danke nochmals, ich werde jetzt mit den ganzen Fragen aufhören aber
> ich finde, diese Douks sind echt s..... geschrieben.

Das hilft leider niemandem.

Sag, was besser gemacht werden muss, dann können wir sehen, was sich
machen lässt.  Alles können wir aber auch nicht ändern, nicht nur aus
mangelnder man power, sondern auch, weil wir ein Tool benutzen um die
Doku automatisch zu generieren, das uns leider nicht x-beliebige
Freiheiten lässt.  So heißt eben die Übersichtsseite nicht "Index"
sondern "List of modules" oder sowas.

Allerdings: bevor du meckerst, nimm bitte aktuelle Versionen.  Ich
finde persönlich (und habe das auch von einigen Leuten bestätigt
bekommen), dass die Doku der avr-libc 1.4 mit ihren Änderungen schon
ein Stück übersichtlicher geworden ist, ganz zu schweigen von den seit
1.4.1 verbesserten Demo-Programmen (es gibt jetzt auch ein stdiodemo).
Dagegen, dass Leute eine Tendenz haben, mit alter Software und Doku
erstmal möglichst lange weiter zu arbeiten, kann nun kein Entwickler
was tun...

von Marian (Gast)


Lesenswert?

Ja, das ist richtig Jörg. Ich war gestern nur etwas frustriert und an
deiner Antwort habe ich gesehen, daß dich meine Fragen schon ein wenig
genervt haben.

Zum Thema Doku: Als allererstes muss ich bemeckern, daß diese Dokus
sehr unübersichtlich sind (vielleicht gehts auch nur mir so) bezüglich
Inhaltsangaben usw.
Und der andere Punkt: Das Problem was ich hatte, wurde in der Doku
leider anders erklärt. So wie du es mir geschrieben hast, stand es
nicht in der Doku drin. Deswegen war ich gestern auch ziemlich
verärgert, denn dann hätte ich die 2 h, die ich so ins suchen
investiert habe, sinnvoller einsetzen könnnen. Aber naja aus Fehlern
lernt man eben.

PS: Reicht es aus, einfach das update von Atmel.com zu installieren, um
auf die neueste avr-libc upzugraden?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Das Problem was ich hatte, wurde in der Doku
> leider anders erklärt.

Das musst du aber bitte erläutern.  Ich finde nichts anderes dort
(auch nicht in alten Versionen) als das, was ich dir geschrieben habe.

Ja, einen ordentlichen Index in der PDF-Datei hätte ich auch gern, ist
leider mit Doxygen wohl nicht drin.  Wenn wir mal viel Zeit haben :),
stellen wir das Dokumentationssytem vielleicht mal auf was anderes um
(Docbook vielleicht), dann sollte sich sowas verbessern lassen.  Im
Moment sind wir froh, dass es zu jedem Release erstmal eine up-to-date
Doku gibt, die auch alles abdeckt, was es an offiziell exportierten
Interfaces in der Bibliothek gibt.

> PS: Reicht es aus, einfach das update von Atmel.com zu installieren,
> um auf die neueste avr-libc upzugraden?

atmel.com, meinst du damit das AVR Studio?  Nein, das hat zwar die
Hooks für den AVR-GCC mittlerweile drin, liefert aber selbst keinen
Compiler mit.  Den muss man sich extern installieren, typischerweise
in Form eines WinAVR.  Mit dem aktuellen WinAVR hast du allerdings
auch die aktuelle avr-libc einschließlich der Doku.

Die Verbesserungen der Übersichtlichkeit der Doku beziehen sich
übrigens auf die HTML-Version, nicht die PDF-Version.  An letzterer
kann ich kaum was im Layout ändern.

von Marian (Gast)


Lesenswert?

Hier war mein liegt mein Problem.

http://www.nongnu.org/avr-libc/user-manual/group__avr__inttypes.html

Und zwar genau in diesem Ausschnitt:
 printf("The hexadecimal value of smallval is " PRIx8
           ", the decimal value of longval is " PRId32 ".\n",
           smallval, longval);

Aufgrund der Anführungszeichen bei den Makros(PRIx8 usw.) dachte ich
halt, ich muss diese auch übernehmen, denn in der Doku muss da ja
richtig sein ;). Ich habe dann viel rumprobiert (mit und ohne und
gemischt) aber nichts aht funktioniert. Als ich dann deine Variante
sah, dachte ich: Nicht wirklich oder? Da hätte man die
Anführungszeichen in der Doku ja auch mal weglassen können. Oder bin
ich der einzige der das so versteht?
Weißt jetzt was ich meine?

PS: Ok, dann werde ich mal versuchen meine Admin zu überreden, mir das
neueste WinAVR zu installieren :).

Gruß Marian

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich begreife allmählich, was du nicht begriffen hast. ;-)

Hmm, ich müsste dich jetzt allerdings in den Kurs ,,Grundlagen von
ANSI-C (ISO-C 1990)'' zurückschicken, zum Stichwort string literal
concetanation.  Du versuchst, ohne dass du dieses Feature von C
verstanden hast, es mit trial&error zu benutzen.  Das geht nicht gut.

Sorry, so viel Zeit, das hier komplett zu erklären, habe ich auch
gerade nicht (ich werde ja schließlich nicht für meine Antworten bei
mikrocontroller.net bezahlt), vielleicht sollte das Thema mal jemand
im Tutorial aufnehmen.  Alternativ: fang einen eigenen Thread dazu an.

Nur kurz:

> #define  PRIx32   "lx";

Lass das Semikolon weg, dann hat das eine Chance zu funktionieren.

> printf("S"lx" ms \n\r",z);

Wenn du das Äquivalent dafür richtig geschrieben haben willst:

printf("S" "lx" "ms \n\r", z);

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

... und das geht natürlich nicht, weil das Prozentzeichen fehlt.


   Nur kurz:

   > #define  PRIx32   "lx";

   Lass das Semikolon weg, dann hat das eine Chance zu
   funktionieren.

   > printf("S"lx" ms \n\r",z);

   Wenn du das Äquivalent dafür richtig geschrieben haben
   willst:

   printf("S" "lx" "ms \n\r", z);



Entweder

  #define PRIx32 "%lx"

oder

  printf("S%" PRIx32 "ms \n\r", z);


Was soll das ganze? Das ist doch ausgesprochen unübersichtlich und
-ganz offensichtlich- auch 'ne wunderschöne Fehlerquelle.

Tip am Rande:

  printf("%08lx", z);

gibt führende Nullen aus.
Das hilft beispielsweise bei tabellarischer Formatierung und ist bei
hexadezimalen Zahlen auch sonst nicht unüblich.

von Marian (Gast)


Lesenswert?

HM...also bei mir hat das auch mit dem Semikolon funktioniert.
Aber du hast recht, es ist ja keine Anweisung.

Das mit printf ist komisch. So wie du das als letztes geschrieben hast,
hatte ich es auch (glaube ich) verstanden, was ja aber nicht
funktioniert hat und es immernoch nicht tut. Nur diese Variante geht:

printf("S%08lx ms \n\r",z);

Warum die 08 drin steht muss ich dir ja sicher nicht erklären ;)...

Nochmals vielen Danke Jörg für die viele Zeit die du für mich geopfert
hast.

PS: Also das mit den String-Literalen versteh ich wirklich nicht.
Meinst du das mir das jemand erklären würde, wenn ich einen neuen
Thread dafür aufmache? Dann heißt es nur wieder: Selber googlen und
nachforschen. (Also werde ich das selber tun :))

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Was soll das ganze? Das ist doch ausgesprochen unübersichtlich und
> -ganz offensichtlich- auch 'ne wunderschöne Fehlerquelle.

C99.  Die Makros kommen aus einem Headerfile (<inttypes.h>).  Damit
wird erreicht, dass man printf()-Formatierungen für benannte
Datentypen schreiben kann, ohne wissen zu müssen, ob ein uint32_t nun
gerade ein short int, int, oder long int in der Maschinen-
repräsentation ist.

Ist also eigentlich nur für die Portabilität wichtig.

> PS: Also das mit den String-Literalen versteh ich wirklich nicht.
> Meinst du das mir das jemand erklären würde, wenn ich einen neuen
> Thread dafür aufmache?

Ich denke schon.  Das Stichwort ist aber "Verkettung von String-
Literalen", also das Zusammenziehen von "aa" "bb" zu "aabb".

von Marian (Gast)


Lesenswert?

OK ich habe mich jetzt darüber informiert. Nun verstehe ich auch die
Schreibweise. Nur eines ist noch unklar: Bei allem was ich gefunden
habe,werden Strings immer mit einem + verkettet.
Z.B.: string name= "Peter"
      s="Der Name lautet" +name+;  //"Der Name lautet Peter"

Das war in der Doku auch nicht so oder irre ich mich schon wieder?
Unübersichtlich finde ich es trotzdem noch :).

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Was auch immer Du da gefunden haben magst, C ist das nicht.
Strinverkettung mit "+" ist Java/JavaScript oder -je nach
Implementierung der Klasse "string"- C++.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Achtung!

Laut meiner Sourcen aus dem Arthernet Projekt gab es zumindest mit der
alten avr-libc ein Problem bei der minimalistischen printf Variante.
Hier ein Auszug aus dem Code:
1
#   if 1
2
    /* %0? does not work with minimalistic printf-variant */
3
    sprintf(outbuf, "%02X ", *((uint8_t *)(adr + i)));
4
#   endif
5
6
#   if 0                    
7
    /* Workaround for minimalistic printf-variant */
8
    if((*((uint8_t *)(adr + i))) >= 0x10)
9
        sprintf(outbuf, "%X ", *((uint8_t *)(adr + i)));
10
    else
11
        sprintf(outbuf, "0%X ", *((uint8_t *)(adr + i)));
12
#   endif

von Marian (Gast)


Lesenswert?

@Rufus:

Oh dann habe ich das wohl übersehen, daß das Java ist. Ich bin halt
noch Anfänger aber alle Codes die ich sah, sahen für mich wie C aus.
Ich hab die Seite nochmals geprüft und du hattest recht, es war eine
Java Seite :(...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Laut meiner Sourcen aus dem Arthernet Projekt gab es zumindest mit
> der alten avr-libc ein Problem bei der minimalistischen printf
> Variante.

Problem ist gut. ;-) It's a feature.  Wenn du die minimalistische
printf-Variante haben willst, dann ist halt (dafür ist sie ja eben
minimalistisch) genau sowas wie die Feldweite nicht implementiert.

Wenn du das nicht magst, dann nimm die Standard-Variante.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Ich weis, das habe ich ja dann auch gelesen.
Was ich da nicht ganz verstehe ist %p...

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
Noch kein Account? Hier anmelden.