Forum: Compiler & IDEs sprintf mit float Frage


von Pete K. (pete77)


Lesenswert?

Hallo,

ich habe ein Problem, dass das Fromatieren von einer float Variablen 
nicht funktioniert.

Die Zuweisung lautet:
1
char buffer[50];
2
float f_ftun;
3
4
sprintf(buffer, "Mhz=%f  ",(double)f_ftun);

Ausgabe: Mhz=?

Libraries sind wie folgt im AVRStudio4.18 gesetzt:
libprintf_flt.a
libm.a
libc.a
libscanf_flt.a


Ausgabe Build:
avr-gcc -mmcu=atmega328p  rda5708m.o twimaster.o uart.o RDA5708M_lib.o 
-lprintf_flt -lm -lc -lscanf_flt  -o rda5708m.elf

Irgendetwas habe ich vergessen, oder?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Pete K. schrieb:
> Irgendetwas habe ich vergessen, oder?

Ja.

Folgende Optionen fehlen:
1
-Wl,-u,vfprintf
2
-Wl,-u,vfscanf

Siehe hier

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

unter vfscanf und vfprintf.

von Pete K. (pete77)


Lesenswert?

Hmm, geht immer noch nicht:

avr-gcc  -mmcu=atmega328p -gdwarf-2 -std=gnu99 -Wall   -Wl,-u,vfprintf 
-lprintf_flt -Wl,-u,vfscanf -lscanf_flt    -lm   -DF_CPU=8000000UL -Os 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums 
-Wl,-u,vfprintf  -Wl,-u,vfscanf  -MD -MP -MT RDA5708M_lib.o -MF 
dep/RDA5708M_lib.o.d  -c  ../RDA5708M_lib.c

avr-gcc -mmcu=atmega328p  rda5708m.o twimaster.o uart.o RDA5708M_lib.o 
-lprintf_flt -lm -lc -lscanf_flt  -o rda5708m.elf

von Pete K. (pete77)


Lesenswert?

Sorry, AVRStudio ist 4.19 Build 730 mit AVR-Toolchain. Macht das einen 
Unterschied?

von Karl H. (kbuchegg)


Lesenswert?

Pete K. schrieb:
> Sorry, AVRStudio ist 4.19 Build 730 mit AVR-Toolchain. Macht das einen
> Unterschied?

Ich hab jetzt die Reihenfolge nicht analysiert, in der die Argumente in 
deinem gcc Aufruf auftauchen, aber die Reihenfolge ist da wichtig.

Halte dich an diese Vorgehensweise
http://www.mikrocontroller.net/articles/FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_bei_WinAVR_bzw_AVR-Studio
und du kriegst das richtige Ergebnis

von Jim M. (turboj)


Lesenswert?

Pete K. schrieb:
> Hmm, geht immer noch nicht:
>
> avr-gcc  -mmcu=atmega328p -gdwarf-2 -std=gnu99 -Wall   -Wl,-u,vfprintf
> -lprintf_flt -Wl,-u,vfscanf -lscanf_flt    -lm   -DF_CPU=8000000UL -Os
> -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
> -Wl,-u,vfprintf  -Wl,-u,vfscanf  -MD -MP -MT RDA5708M_lib.o -MF
> dep/RDA5708M_lib.o.d  -c  ../RDA5708M_lib.c

Die "-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt    -lm"

sind IMO Optionen für den Linker und nicht für den Compiler.

Folglich gehören sie unten rein:

> avr-gcc -mmcu=atmega328p  rda5708m.o twimaster.o uart.o RDA5708M_lib.o
> -lprintf_flt -lm -lc -lscanf_flt  -o rda5708m.elf

von Eric B. (beric)


Lesenswert?

Pete K. schrieb:
> Hallo,
>
> ich habe ein Problem, dass das Fromatieren von einer float Variablen
> nicht funktioniert.
>
> Die Zuweisung lautet:
>
1
> char buffer[50];
2
> float f_ftun;
3
> 
4
> sprintf(buffer, "Mhz=%f  ",(double)f_ftun);
5
>
>
> Ausgabe: Mhz=?

Warum wird f_ftun nach double gecastet? (Für double bräuchtest du %lf 
im Formatstring statt %f)
Und welcher Wert hat f_ftun? (Im obigen Code-Schnipsel ist das 
undefiniert)

Was passiert wenn du den Code wie folgt änderst:
1
char buffer[50];
2
float f_ftun = 3.14;
3
 
4
sprintf(buffer, "Mhz=%f  ", f_ftun);

von Dirk B. (dirkb2)


Lesenswert?

Eric B. schrieb:
> Für double bräuchtest du %lf
> im Formatstring statt %f)

Das ist Unfug.

1. Werden bei Funktionen mit variabler Argumentenliste (dazu gehört auch 
printf) float als double übergeben.
2. Ergibt sich daraus, dass %f sowohl für double als auch float gilt.
(seit C11 ist aber auch %lf gültig. Wohl aus Resignation)

Beachte, dass die 2. Aussage nur für die printf-Familie gilt.
(scanf ist eine ganz andere Funktion. Da werden Pointer übergeben)

von Karl H. (kbuchegg)


Lesenswert?

Dirk B. schrieb:

> (seit C11 ist aber auch %lf gültig. Wohl aus Resignation)

Nicht ganz.
Es vereinfacht die Verwaltung von Format Strings, wenn man die zb aus 
Datenbanken zulädt. Dann benötigt man keine Unterscheidung, ob der 
Formatstring für printf oder für scanf benutzt werden soll.

von Markus F. (mfro)


Lesenswert?

Dirk B. schrieb:
> 1. Werden bei Funktionen mit variabler Argumentenliste (dazu gehört auch
> printf) float als double übergeben.

Richtig.

Der Cast ist trotzdem weder notwendig noch sinnvoll, da sorgt der 
Compiler schon selbst dafür.

von Micca (Gast)


Lesenswert?

Ich komme zwar aus der C Welt, aber ich habe nie verstanden, warum alle 
Welt mit (s)printf arbeitet. Eine der häufigsten Probleme mit Ausgabe 
von Daten liegt an den (s)printf Formatierstrings...
Einmal in C++ mit Typsicheren Streams gearbeitet und ich wollte nie mehr 
zurück (musste es aber, weil C im embedded halt nicht tot zu kriegen 
ist...)

Ein Kollege hat es so gelöst, er hat sich einzelne Aufrufe gebastelt:
(aus dem Gedächtnis...)
1
inline void printInt32(int32 x) {printf("%i",x);}
2
inline void printFloat(float x) {printf("%i",x);}
3
inline void printString(char x[]) {printf("%i",x);}

Ist am Anfang gewöhnungsbedürftig, aber jetzt meckert der Compiler, wenn 
man den falschen Typ nutzt.

Wenn's der C Compiler kann wäre jetzt natürlich Polymorphie das Mittel 
der Wahl:
(aus dem Gedächtnis...)
1
inline void print(int32 x) {printf("%i",x);}
2
inline void print(float x) {printf("%i",x);}
3
inline void print(char x[]) {printf("%i",x);}

von Dirk B. (dirkb2)


Lesenswert?

Micca schrieb:
> aber ich habe nie verstanden, warum alle
> Welt mit (s)printf arbeitet.

Weil es in C nichts anderes gibt.
(und weil die Formatierung bei cout umständlich ist.)

Micca schrieb:
> aber jetzt meckert der Compiler, wenn
> man den falschen Typ nutzt.
Der Compiler meckert auch bei printf. Allerdings als Warnung, wenn man 
sie aktiviert.
Wenn man weiß was man tut, ist C ok. (aber wer weiß das schon)

von Micca (Gast)


Lesenswert?

>Der Compiler meckert auch bei printf. Allerdings als Warnung, wenn man
sie aktiviert.
Korrekt. Inzischen können viele Toolchains Warnings werfen.
Aber ich seh das so: jetzt habe ich eine streng typisierte Sprache und 
entdecke den Fehler erst zur Laufzeit.

>Weil es in C nichts anderes gibt
Jepp, die Std Libs geben nichts her. Hinzu kommt, dass printf nicht 
gerade wenig Speicher benötigt.

>Wenn man weiß was man tut, ist C ok. (aber wer weiß das schon)
:-)

von Rolf Magnus (Gast)


Lesenswert?

Micca schrieb:
>>Der Compiler meckert auch bei printf. Allerdings als Warnung, wenn man
> sie aktiviert.
> Korrekt. Inzischen können viele Toolchains Warnings werfen.

Und früher haben sie sie einfach nur ausgegeben?

Micca schrieb:
> Wenn's der C Compiler kann wäre jetzt natürlich Polymorphie das Mittel
> der Wahl:
> (aus dem Gedächtnis...)
> inline void print(int32 x) {printf("%i",x);}
> inline void print(float x) {printf("%i",x);}
> inline void print(char x[]) {printf("%i",x);}

Das hat nichts mit Polymorphie zu tun. Das ist einfache 
Funktionsüberladung.

von Karl H. (kbuchegg)


Lesenswert?

Micca schrieb:
> Ich komme zwar aus der C Welt, aber ich habe nie verstanden, warum alle
> Welt mit (s)printf arbeitet.

Weil man mit dem Formatstring eine ganze Latte an Formatierproblemen auf 
einfache und auf wenig geschwätzige Art und Weise in den Griff kriegt. 
Versuch mal einen int als Hex-Zahl auszugeben und dabei führende 0-en 
auf 4 hexadezimale Digits zu erhalten. Klar, ist mit den C++ Streams 
machbar, aber dann doch schon sehr geschwätzig.

> Ein Kollege hat es so gelöst, er hat sich einzelne Aufrufe gebastelt:
> (aus dem Gedächtnis...)
>
1
> inline void printInt32(int32 x) {printf("%i",x);}
2
> inline void printFloat(float x) {printf("%i",x);}
3
> inline void printString(char x[]) {printf("%i",x);}
4
>

in dem Fall ist er aber eine Pfeife. Was bringt ihm hier ein printf im 
Vergleich zu zb einem itoa-puts Gespann? Richtig. Genau gar nichts. Das 
wäre genau so typsicher und hat den ganzen printf Overhead nicht. printf 
bringt dir nur dann was, wenn du die Möglichkeiten des Formatstrings zu 
deinem Vorteil ausnutzen kannst. Leider scheint es so zu sein, dass mehr 
als 60% der 'neuen' C Programmierer gar nicht mehr wissen, was man mit 
dem Formatstring alles anstellen kann und welche Möglichkeiten man da 
hat.

Schreib mal das Äquivalent zu
1
uint8_t hour, minute, second
2
char buffer[10];
3
4
  sprintf( buffer, "%02d:%02d:%02d", hour, minute, second );
5
  lcd_puts( buffer );
(und ja, ich bestehe darauf, dass die Ausgabe nicht an irgendeine 
Konsole geht, sondern auf ein LCD)

Das man bei den Angaben im Formatstring aufpassen muss, ist schon 
richtig. Aber so schlimm ist das jetzt auch wieder nicht, wenn man sich 
daran gewöhnt hat, dass man in der ganzen Programmierung an jeder 
einzelnen Stelle aufpassen und sorgfältig sein muss.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Dirk B. schrieb:
> Micca schrieb:
>> aber ich habe nie verstanden, warum alle
>> Welt mit (s)printf arbeitet.
>
> Weil es in C nichts anderes gibt.
> (und weil die Formatierung bei cout umständlich ist.)

Es gibt wohl bisher kein anderes Konzept für die Ausgabeformatierung,
das so leicht und übersichtlich anzuwenden ist (siehe Beispiel von Karl
Heinz). Deswegen haben sehr viele Programmiersprachen (auf Kosten der
Compile-Zeit-Typsicherheit) ein printf- oder sprintf-Äquivalent:

  http://en.wikipedia.org/wiki/Printf_format_string#Programming_languages_with_printf

Auch C#, F#, Visual Basic, Common Lisp und viele weitere Sprachen haben
Formatierungsfunktionen, die nach demselben Prinzip – nur mit einer
anderen Formatsyntax – arbeiten.

Ich selber benutze printf und seine Äquivalent eigentlich auch ganz
gerne (nicht nur in C). Der Wegfall der statischen Typsicherheit ist
zwar unschön, aber auch kein allzu großes Problem, weil nicht zum
Formatstring passende Datentypen in ansonsten statisch typisierten
Sprachen i.Allg. schon beim ersten Probelauf, bei dem das printf in
Aktion tritt, auffallen.


Rolf Magnus schrieb:
> Micca schrieb:
>> Wenn's der C Compiler kann wäre jetzt natürlich Polymorphie das Mittel
>> der Wahl:
>> (aus dem Gedächtnis...)
>> inline void print(int32 x) {printf("%i",x);}
>> inline void print(float x) {printf("%i",x);}
>> inline void print(char x[]) {printf("%i",x);}
>
> Das hat nichts mit Polymorphie zu tun. Das ist einfache
> Funktionsüberladung.

... auch bekannt als Ad-Hoc-Polymorphie ;-)

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.