Archiv verlassen und diese Seite im Standarddesign anzeigen : [C] vsprintf + float -> IDE bezogene Probleme?
Hi,
ich nutze sei einiger Zeit vsprintf auf einem Mikrocontroller. Die Funktion, die ich mit vsprintf() geschrieben habe, funktioniert eigentlich ganz gut - es gibt aber ein Problem. Und zwar dann wenn ich mit %f einen Float Wert übergeben will.
meine Funktion sieht so aus:
int WriteFile(char *format, ...)
{
...
}
Funktionsaufrufe:
return_wert = WriteFile("Wert=%d",wert); //hier funktioniert alles bestens
return_wert = WriteFile("Wert=%f",wert_float); //das funktioniert nicht
Die Parameterübergabe der float Variable funktioniert nicht. Bei einer Recherche im Internet hab ich herausgefunden, dass einige Leute mit vsprintf() + float Probleme haben.
Was ich jedoch noch nicht herausfinden konnte: Sind diese Probleme auf die verwendete IDE und dessen Implentierung von vsprintf() zurückzuführen oder kann ich generell mit vsprintf() keine float Werte übergeben?
Danke!
ContainerDriver
19-03-2009, 21:38
Hallo,
was heißt denn es funktioniert nicht? Lässt es sich nicht kompilieren?
Gruß, Florian
Hi Florian,
es lässt sich kompilieren.
Der Sourcecode der Funktion WriteFile:
int WriteFile(char *format, ...)
{
va_list args;
va_start(args,format);
vsprintf(filename,format,args);
[....]
}
Wenn ich die Funktion nun mit dem float Parameter aufrufe, dann steht in der Variable 'filename' etwas random-mäßiges.
Der folgende Thread beschreibt die Problematik:
http://raisonance-forum.xsalto.com/viewtopic.php?id=1628
ContainerDriver
19-03-2009, 22:02
Welchen Kompiler verwendest du?
Ich habe leider keine Ahnung von Microcontrollern, das Problem könnte aber schon auf eine fehlerhafte Implementierung von vsprintf zurückzuführen sein; prinzipiell kann man an vsprintf schon float Werte übergeben.
Hast du vielleicht noch andere Fehler in deinem Programm (char-Felder zu klein o.ä.)?
Die Array Größe sollte passen - sogar schon mal größer eingestellt, hat sich aber nichts geändert.
Compiler: Raisonance Ride
Gibts da vielleicht eine Möglichkeit wie man dem vsprintf() eine float Unterstützung beibringen könnte? Oder ist das ein gravierender Eingriff? Hab da relativ wenig Ahnung von der Materie...
ContainerDriver
19-03-2009, 23:18
Du könntest vsprintf selbst implementieren, es ist allerdings fraglich, ob die float-Werte überhaupt richtig mit va_list übergeben werden. Ich würde erstmal ein Minimalbeispiel mit vsprintf + float-Werte ausprobieren und falls das nicht geht überprüfen, ob du grundsätzlich float-Werte mit va_list übergeben kannst.
afaik kanns probleme geben wenn du xprintf (x in {,f,vf,s,...}) für floats und doubles verwenden willst aber keine implementation von sbrk für den controller hast. (sbrk wird von malloc und co gebraucht um speicher auf dem heap anzufordern).
Hi,
ich hab jetzt mal ein Miniprogramm geschrieben und zwar mit einer sprintf() Funktion.
Also:
sprintf(filename, "%f", wert);
Wenn ich dann den String in der Variable 'filename' ausgebe, dann seh ich den Float Wert. Sollte also passen?!
Ich nehm mal an der Fehler liegt wie von Florian vermutet beim va_list...
Wie kann ich herausfinden ob ich eine Implentation von sbrk hab?
ContainerDriver
20-03-2009, 18:32
Das weiß ich auch nicht so genau, vielleicht kannst du einfach mal sbrk-Aufruf in deinen Code setzen? Allerdings würde dein Testergebnis in Verbindung mit jeebees-Posting bedeuten, dass sbrk funktioniert.
Hast du schon mal versucht, eine va_list manuell durchzugehen (mit va_arg())?
wenn sprintf mit floats funktioniert, kanns eigentlich nicht das sbrk-problem sein.
#include <stdarg.h>
#include <string.h>
float wert=1.34567;
int WriteFile(char *format, ...)
{
char xdata filename[60];
float zahl;
va_list args;
va_start(args,format);
zahl = va_arg(args,float);
printf("Zahl=%f\n",zahl); //hier wird das richtige (also 1.34567) ausgegeben
va_end(args);
}
void main()
{
//UART initialisieren
for(;;)
{
if(RI == 1)
{
WriteFile("Wert=%f\n",wert);
RI = 0;
}
}
}
Komisch, mit va_arg funktionierts...
Jemand eine Idee was da bei vsprintf() schieflaufen könnte?
ContainerDriver
21-03-2009, 09:38
Also entweder die vsprintf-Implementation ist fehlerhaft, oder in deinem Code steckt noch irgendwo ein Fehler. Wie groß ist denn dein Programm? Kannst du es vielleicht hier mal posten oder ein Minimalbeispiel schreiben, bei der vsprintf mit float-Zahlen nicht funktioniert?
Hier ein Minimalbeispiel mit vsprintf das nicht funktioniert:
#include <string.h>
#include <stdarg.h>
float wert=1.34567;
int WriteFile(char *format, ...)
{
char xdata filename[60];
va_list args;
va_start(args,format);
vsprintf(filename,format,args);
printf("%s",filename); //als Ausgabe bekomm ich: Wert=
va_end(args);
}
void main()
{
//UART initialisieren
for(;;)
{
if(RI == 1)
{
WriteFile("Wert=%f\n",wert);
RI = 0;
}
}
}
ContainerDriver
21-03-2009, 11:19
Danke, das sollte so eigentlich schon funktionieren. Leider weiß ich jetzt auch nicht weiter... als einziger Vorschlag fällt mir nur ein, vsprintf selber zu schreiben, da ja prinzipiell die Übergabe von float-Werten mit va_list geht.
Gruß, Florian
Hi Florian,
hast du vielleicht einen Ansatz wie ich vsprintf() selbst schreiben kann?
Würde mir sehr helfen. Mit welchem Programmumfang muss ich rechnen?
edit: Ich glaub ich hab eine Idee. Bin natürlich auch noch an Ideen von euch interessiert :)
Meine wird wahrscheinlich eh nicht klappen..
ContainerDriver
22-03-2009, 14:17
Hi Florian,
hast du vielleicht einen Ansatz wie ich vsprintf() selbst schreiben kann?
Würde mir sehr helfen. Mit welchem Programmumfang muss ich rechnen?
edit: Ich glaub ich hab eine Idee. Bin natürlich auch noch an Ideen von euch interessiert :)
Meine wird wahrscheinlich eh nicht klappen..
Was ist denn deine Idee?
Ich würde einfach den übergebenen String nach %-Zeichen durchsuchen; wenn ein % gefunden wird, den angegebenen Datentyp bestimmen und mit va_arg ein Argument aus der Liste ziehen (Sonderfall %% beachten) und das Argument im Zielstring abspeichern. Zeichen, die nicht ein % sind, bzw. nicht nach einem % stehen, musst du natürlich auch in den Zielstring übernehmen. In der Manpage zu va_arg (http://linux.die.net/man/3/va_arg) steht bei Example Code, den du verwenden kannst.
Hi,
entschuldige die etwas späte Antwort.
Mein Lösungsansatz wäre gewesen, die float Problematik durch Festkommaarithmetik komplett zu umgehen. Aber dies würde ich nur ungern machen, würde viel Arbeitsaufwand bedeuten.
Deine Lösung klingt echt vielversprechend. Ich werd mal schauen ob und wie man das möglichst resourcenschonend integrieren kann. Danke für den Tipp!
Ich bins wieder mit einem kleinen Update und einer erneuten Frage.
Ich hab jetzt vom Hersteller das C-File für vsprintf() bekommen. Angeblich ist beim Bauen der Library etwas schiefgegangen, sodass die float Unterstützung nicht implementiert wurde. Ich möchte nun die vsprintf() Funktion, die in der stdio.h drinnen ist durch die neue ersetzen. Nur wie geh ich da am besten vor?
In der stdio.h hab ich folgenden Eintrag gefunden:
extern int vsprintf ( char *, const char *, va_list ) reentrant;
Genügt es da jetzt einfach diesen auszukommentieren, damit der Compiler das alte vsprintf() nicht mehr kennt? (Hier sei zu erähnen ich habe nicht viel Ahnung von Libraries + Headerfiles in C)
Ich hätte mir gedacht, ich probier das mal und kopiere den Sourcecode den ich bekommen habe einfach in mein main.c File zum restlichen Sourcecode. Das Compilieren funktioniert ohne Probleme, doch wenn ich das dann ausführe dann steht im String den ich ausgeben will wirre Zeichen.
ContainerDriver
27-03-2009, 22:43
Im Header wird dem Compiler einfach nur bekannt gemacht, dass es eine solche Funktion irgendwo geben soll, auskommentieren musst du dort eigentlich nichts.
Ich vermute, wenn du den Code von vsprintf direkt in deinen Quellcode kopierst, wird immer noch die alte Funktion (die aus der entsprechenden Bibliothek) verwendet.
Am schnellsten würde es gehen, du benennst vsprintf bei der Funktionsdefinition einfach um und rufst dann die umbenannte Funktion auf.
Gruß, Florian
Es gäbe noch einen hackischen Ansatz: Mach aus WriteFile ein Makro, um zu verhindern vsnprintf zu verwenden:
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
float wert=1.34567;
#define WriteFile(format, ...) \
{ \
char __filename[60]; \
snprintf(__filename, 60, format, ## __VA_ARGS__); \
printf("%s",__filename); \
}
int main()
{
WriteFile("Wert=%f\n",wert);
return 0;
}
Das funktioniert jedenfalls mit gcc:
$ gcc -Wall -std=c99 -pedantic -g -O2 -o WriteFile WriteFile.c
$ ./WriteFile
Wert=1.345670
Ah, hatte übersehn das es eine 2. Seite gibt.
Hi,
das mit dem Umbenennen von vsprintf() hat leider nicht geklappt - wenn ich die Funktion aufrufe, dann werden beim printf() Random Zeichen ausgegeben.
Die Methode von panzi würd sich gut anhören - leider bekomm ich aber folgenden Compiler Fehler:
'...' is not a valid identifier
Hi,
das mit dem Umbenennen von vsprintf() hat leider nicht geklappt - wenn ich die Funktion aufrufe, dann werden beim printf() Random Zeichen ausgegeben.
Die Methode von panzi würd sich gut anhören - leider bekomm ich aber folgenden Compiler Fehler:
'...' is not a valid identifier
Tjo dann ists kein C99 kompatibler Compiler. Dann weiß ich auch net weiter.
Powered by vBulletin® Version 4.2.5 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.