2009-05-25 16 views
22

Guys, ich möchte wissen, ob float Variablen in sprintf() Funktion verwendet werden können.Verwendung von Schwimmern mit sprintf() in eingebetteten C

Wie, wenn wir schreiben:

sprintf(str,"adc_read = %d \n",adc_read); 

wo adc_read eine Integer-Variable ist, wird es die Zeichenfolge speichern

"adc_read = 1023 \n"

in str (unter der Annahme, dass adc_read = 1023)

Wie kann ich Verwenden Sie eine Float-Variable anstelle von Integer?

+0

Welche C-Bibliothek verknüpfen Sie gegen? – sybreon

+1

Hinweis: Sie versuchen, ein Double zu formatieren. Mit Varargs wird der Compiler einen Float-Wert automatisch verdoppeln. – Richard

+3

"Embedded", Jungs. Das ist der Schlüssel. Es spielt keine Rolle, was Ihre Fancy-Shmany-Bibliotheken auf Ihren Rechnern mit GB Speicher machen :-) Embedded-Plattformen haben in der Regel Kompromisse, die auf minimalen Speicherbedarf abzielen. – paxdiablo

Antwort

40

Da Sie sich auf einer Embedded-Plattform befinden, ist es durchaus möglich, dass Sie nicht über die volle Funktionalität der printf()-Funktionen verfügen.

Angenommen, Sie Schwimmer überhaupt haben (noch nicht unbedingt ein für eingebettete Sachen gegeben), können Sie es mit so etwas wie emulieren kann:

char str[100]; 
float adc_read = 678.0123; 

char *tmpSign = (adc_read < 0) ? "-" : ""; 
float tmpVal = (adc_read < 0) ? -adc_read : adc_read; 

int tmpInt1 = tmpVal;     // Get the integer (678). 
float tmpFrac = tmpVal - tmpInt1;  // Get fraction (0.0123). 
int tmpInt2 = trunc(tmpFrac * 10000); // Turn into integer (123). 

// Print as parts, note that you need 0-padding for fractional bit. 

sprintf (str, "adc_read = %s%d.%04d\n", tmpSign, tmpInt1, tmpInt2); 

Sie werden beschränken müssen, wie viele Zeichen kommen, nachdem das Dezimalsystem basiert über die Größe deiner Ganzzahlen.Bei einer 16-Bit-Ganzzahl mit Vorzeichen sind Sie beispielsweise auf vier Ziffern beschränkt (9.999 ist die größte Zehnerpotenz, die dargestellt werden kann).

Es gibt jedoch Möglichkeiten, dies zu handhaben, indem Sie den Bruchteil weiterverarbeiten und ihn jedesmal um vier Dezimalstellen verschieben (und den Ganzzahlteil verwenden/subtrahieren), bis Sie die gewünschte Genauigkeit haben.


Update:

Ein letzter Punkt, den Sie erwähnten, dass Sie avr-gcc in einer Antwort auf eine der anderen Antworten wurden unter Verwendung. Ich habe die folgende Webseite gefunden, die zu beschreiben scheint, was Sie tun müssen, um %f in Ihren printf() Anweisungen here zu verwenden.

Wie ich ursprünglich vermutet habe, müssen Sie zusätzliche Beinarbeit leisten, um Gleitkommaunterstützung zu bekommen. Dies liegt daran, dass eingebettete Sachen selten Gleitkommazahl benötigen (zumindest nichts von dem, was ich jemals getan habe). Sie müssen zusätzliche Parameter in Ihrem Makefile festlegen und mit zusätzlichen Bibliotheken verknüpfen.

Dies wird jedoch wahrscheinlich Ihre Code-Größe aufgrund der Notwendigkeit, allgemeine Ausgabeformate zu handhaben ziemlich viel erhöhen. Wenn Sie Ihre Float-Ausgaben auf 4 Dezimalstellen oder weniger beschränken können, würde ich vorschlagen, meinen Code in eine Funktion umzuwandeln und nur diese zu verwenden - es wird wahrscheinlich viel weniger Platz einnehmen.

Falls das jemals Link verschwindet, was Sie tun müssen, ist sicherzustellen, dass Ihr gcc Befehl "-Wl,-u,vfprintf -lprintf_flt -lm“hat Dies führt zu:.

  • Kraft vfprintf zunächst nicht definiert werden (so dass der Linker zu lösen hat it).
  • geben sie die Floating-Point-printf() Bibliothek für die Suche.
  • die Mathematik-Bibliothek angeben für die Suche.
+0

, die ein netter Trick ist, werde ich versuchen, es aus thanx – aditya

+0

es Kompilierungsfehler Fehler ist zu geben: erwartete Ausdruck vor ‚int‘ in obigen Code in Zeile 5 – aditya

+0

Sorry, zu viel Java. Siehe Aktualisierung. – paxdiablo

0

die %f Modifikator:

sprintf (str, "adc_read = %f\n", adc_read); 

Zum Beispiel:

#include <stdio.h> 

int main (void) 
{ 
    float x = 2.5; 
    char y[200]; 

    sprintf(y, "x = %f\n", x); 
    printf(y); 
    return 0; 
} 

ergibt dies:

x = 2.500000

+1

Ich tat, aber es hat nicht funktioniert \t es druckt ein? Zeichen anstelle der Zeichenfolge – aditya

-2

Ja, verwenden Sie% f

+0

Ich habe, aber es hat nicht funktioniert – aditya

+1

es druckt ein? Zeichen anstelle der Zeichenfolge. – aditya

+0

Wie hat es nicht funktioniert? Falsche Ausgabe? – rein

0

Ja natürlich gibt ist nichts besonderes mit Schwimmern. Sie können die Formatzeichenfolgen verwenden, die Sie in printf() für Gleitkommazahlen und andere Datentypen verwenden.

EDIT habe ich versucht, diesen Beispielcode:

float x = 0.61; 
char buf[10]; 
sprintf(buf, "Test=%.2f", x); 
printf(buf); 

Ausgang war: Test = 0,61

+0

tat ich, aber es hat nicht funktioniert \t es druckt ein? Zeichen anstelle der Zeichenfolge – aditya

+0

Siehe die Bearbeitung für meinen Beispielcode .. Ich habe das Gefühl, dass Ihr Puffer "str" ​​zu klein ist..try mit etwas ähnliches% .2f, um die Genauigkeit einzustellen. – Naveen

+0

Größe meines Puffers ist 100 tatsächlich, ich drucke es auf der seriellen Schnittstelle, so denke ich, Problem bei der Übertragung float-Variablen über UART – aditya

2

Ja, Sie können. Es hängt jedoch von der C-Bibliothek ab, gegen die Sie verlinken, und Sie müssen sich der Konsequenzen bewusst sein.

Da Sie für Embedded-Anwendungen programmieren, stellen Sie fest, dass die Gleitkommaunterstützung für viele eingebettete Architekturen emuliert wird. Durch das Kompilieren dieser Gleitkommaunterstützung wird die Größe der ausführbaren Datei erheblich erhöht.

+0

ich verwende avr-gcc – aditya

1

Erwarten Sie nicht, dass sprintf (oder eine andere Funktion mit varargs) automatisch etwas ansteuert. Der Compiler versucht nicht, die Formatzeichenfolge zu lesen und die Umwandlung für Sie auszuführen. Zur Laufzeit hat sprintf keine Meta-Informationen verfügbar, um zu bestimmen, was sich auf dem Stack befindet. es öffnet nur Bytes und interpretiert sie wie in der Formatzeichenfolge angegeben. sprintf (myvar, "% 0", 0); sofort segfaults.

Also: Die Formatzeichenfolgen und die anderen Argumente müssen übereinstimmen!

0

Ja und nein. Trotz allem, was einige andere Antworten gesagt haben, ist der C-Compiler erforderlichen Konvertierungen für sprintf() auszuführen, und alle anderen variadische Funktionen wie folgt:

  • char =>int
  • short =>int
  • float =>double

(und mit/ohne Vorzeichen Varianten des ab ove Integral-Typen)

Es tut dies, gerade weil sprintf() (und die anderen print() -Familie Funktionen) wäre ohne sie unbrauchbar. (Natürlich, they're pretty unusable as it is.)

Aber Sie können keine anderen Konvertierungen annehmen, und Ihr Code wird undefiniertes Verhalten haben - lesen: Absturz! - wenn du es machst.

+1

Der Compiler muss _Conversions_ ausführen. Ein _cast_ wird explizit vom Programmierer angefordert. – mlp

+0

fairer Kommentar. Jetzt reparieren – dcw

+1

"Unbrauchbar" ist ein ziemlich starkes Wort. Die printf() Familie ist ziemlich brauchbar, aber nicht perfekt. Es hat offensichtliche Fehler in der Typsicherheit, aber der Compiler kann in 99% der Anwendungsfälle leicht die Typen der übergebenen Argumente überprüfen und Ihnen eine Warnung/einen Fehler geben (siehe gcc's -Wformat et al). –

0

Suchen Sie in der Dokumentation für sprintf für Ihre Plattform. Es ist normalerweise% f oder% e. Der einzige Ort, an dem Sie eine definitive Antwort finden, ist die Dokumentation ... Wenn Sie nicht dokumentiert sind, können Sie sich an den Lieferanten wenden.

Welche Plattform ist das? Jemand könnte bereits wissen, wo die Dokumente sind ... :)

+0

ist es Atmega128 Mikrocontroller Der Compiler ist avr-gcc. Danke für die Antwort, aber die Antwort von Pax hat perfekt funktioniert. – aditya

0

Tun Sie dies nicht; Ganzzahlen in C/C++ werden immer abgerundet, sodass die Funktion floor nicht benötigt wird.

char str[100]; 
int d1 = value; 

Bessere

int d1 = (int)(floor(value)); 

Dann verwenden Sie nicht aus dem ganzzahligen Teil erhalten Rundung (68,9999999999999999 wird 69.00 ..). 68.09999847 statt 68.1 ist schwer zu vermeiden - jedes Fließkommaformat hat eine begrenzte Genauigkeit.

3

Ist das nicht so etwas wie dies wirklich einfacher:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

char str[10]; 
float adc_read = 678.0123; 

dtostrf(adc_read, 3, 4, temp); 
sprintf(str,"adc_read = %10s \n", temp); 
printf(temp); 
+0

ja es funktionierte gut für mich nach Stunden der Suche, danke –

+0

Es ist einfacher, aber es funktioniert nicht, wenn Sie nicht stdlib einbetten können, weil Sie einen winzigen Mikrocontroller zielen. – Funkodebat

0

% g dies tun können:

#include <stdio.h> 
int main() { 
    float w = 234.567; 
    char x[__SIZEOF_FLOAT__]; 
    sprintf(x, "%g", w); 
    puts(x); 
}