wake-up-neo.com

Floats mit sprintf () in eingebettetem C verwenden

Leute, ich möchte wissen, ob float-Variablen in sprintf()-Funktion verwendet werden können.

Wenn wir schreiben:

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

wenn adc_read eine Ganzzahlvariable ist, wird die Zeichenfolge gespeichert 

"adc_read = 1023 \n" 

in str (vorausgesetzt, dass adc_read = 1023)

Wie kann ich eine Float-Variable anstelle von Integer verwenden?

24
aditya

Da Sie sich auf einer Embedded-Plattform befinden, ist es sehr wahrscheinlich, dass Sie nicht alle Funktionen der printf()- Funktionen nutzen können.

Vorausgesetzt, Sie haben überhaupt Floats (immer noch nicht unbedingt eine Angabe für eingebettetes Zeug), können Sie dies mit etwas wie dem folgenden simulieren:

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 müssen die Anzahl der Zeichen nach der Dezimalstelle einschränken, je nach Größe der Ganzzahl. Bei einer vorzeichenbehafteten 16-Bit-Ganzzahl sind Sie beispielsweise auf vier Stellen beschränkt (9.999 ist die größte Zehnerpotenz minus 1, die dargestellt werden kann).

Es gibt jedoch Möglichkeiten, dies zu tun, indem der gebrochene Teil weiter verarbeitet und jedes Mal um vier Dezimalstellen verschoben wird (und der ganzzahlige Teil verwendet/subtrahiert wird), bis Sie die gewünschte Genauigkeit haben.


Update:

Ein letzter Punkt, den Sie erwähnt haben, dass Sie avr-gcc in einer Antwort auf eine der anderen Antworten verwendet haben. Ich habe die folgende Webseite gefunden, die anscheinend beschreibt, was Sie tun müssen, um %f in Ihren printf()-Anweisungen hier zu verwenden.

Wie ich ursprünglich vermutete, müssen Sie einige zusätzliche Beinarbeit leisten, um Unterstützung für Fließkommazahlen zu erhalten. Dies liegt daran, dass eingebettetes Material selten Fließkomma benötigt (zumindest keines der Dinge, die ich je gemacht habe). Dazu müssen Sie zusätzliche Parameter in Ihrem Makefile festlegen und mit zusätzlichen Bibliotheken verknüpfen.

Aufgrund der Notwendigkeit, mit allgemeinen Ausgabeformaten umgehen zu müssen, erhöht dies wahrscheinlich die Codegröße erheblich. Wenn Sie die Float-Ausgaben auf 4 Dezimalstellen oder weniger beschränken können, würde ich vorschlagen, meinen Code in eine Funktion umzuwandeln und diese Funktion zu verwenden - dies nimmt wahrscheinlich viel weniger Platz in Anspruch.

Falls dieser Link überhaupt nicht mehr angezeigt wird, müssen Sie sicherstellen, dass Ihr gcc-Befehl "-Wl,-u,vfprintf -lprintf_flt -lm "hat. Dies bedeutet:

  • erzwinge, dass vfprintf anfangs undefiniert ist (damit der Linker es auflösen muss).
  • geben Sie die Fließkommabibliothek printf() für die Suche an.
  • geben Sie die mathematische Bibliothek für die Suche an.
44
paxdiablo

Ist so etwas nicht 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);
3
crharper

Ja, du kannst. Es hängt jedoch von der C-Bibliothek ab, mit der Sie verknüpfen, und Sie müssen sich der Konsequenzen bewusst sein.

Da Sie für Embedded-Anwendungen programmieren, sollten Sie sich bewusst machen, dass die Unterstützung von Fließkomma für viele Embedded-Architekturen emuliert wird. Das Kompilieren in dieser Gleitkomma-Unterstützung erhöht letztendlich die Größe Ihrer ausführbaren Datei erheblich.

2
sybreon

Erwarten Sie nicht, dass sprintf (oder eine andere Funktion mit varargs) automatisch etwas auswirkt. Der Compiler versucht nicht, die Formatzeichenfolge zu lesen und den Cast für Sie auszuführen. Zur Laufzeit stehen für Sprintf keine Metainformationen zur Verfügung, um festzustellen, was sich auf dem Stapel befindet. es öffnet einfach Bytes und interpretiert sie wie durch die Formatzeichenfolge angegeben. sprintf (myvar, "% 0", 0); sofort segfaults.

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

1

Ja und nein. Trotz einiger anderer Antworten war der C-Compiler is erforderlich, um Konvertierungen für sprintf() und alle anderen variadischen Funktionen wie folgt durchzuführen:

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

(und vorzeichenbehaftete/vorzeichenlose Varianten der obigen Integraltypen)

Dies geschieht genau deshalb, weil sprintf() (und die anderen print()-Familienfunktionen) ohne es unbrauchbar wären. (Natürlich sind sie sind ziemlich unbrauchbar .)

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

0
dcw

Tu das nicht; Ganzzahlen in C/C++ werden immer abgerundet, sodass die Floor-Funktion nicht verwendet werden muss.

char str[100]; 
int d1 = value;

Besser zu benutzen 

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

Dann wird der ganzzahlige Teil nicht gerundet (68.9999999999999999 wird zu 69,00 ..) ..__ 68.09999847 anstelle von 68.1 ist schwer zu vermeiden - jedes Gleitkomma-Format hat eine begrenzte Genauigkeit.

0
setltd

% g kann das:

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

verwenden Sie den Modifizierer %f:

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

0
Nathan Fellman

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

EDIT Ich habe diesen Beispielcode ausprobiert:

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

Die Ausgabe war: Test = 0,61

0
Naveen

Sehen Sie in der Dokumentation nach sprintf für Ihre Plattform. Es ist normalerweise% f oder% e. Der einzige Ort, an dem Sie eine eindeutige Antwort finden, ist die Dokumentation. Wenn dies nicht dokumentiert ist, können Sie den Lieferanten kontaktieren.

Welche Plattform ist das? Vielleicht weiß schon jemand, wo die Dokumente sind ... :)

0
jheriko

Viele eingebettete Systeme verfügen über eine eingeschränkte snprintf-Funktion, die keine Floats verarbeitet. Ich habe das geschrieben und es macht den Trick ziemlich effizient. Ich habe mich für 64-Bit-Ganzzahlen ohne Vorzeichen entschieden, um große Floats verarbeiten zu können. Sie können diese also auf 16-Bit oder andere Anforderungen mit begrenzten Ressourcen reduzieren.

#include <stdio.h>   // for uint64_t support.


int  snprintf_fp( char destination[], size_t available_chars, int decimal_digits,
                  char tail[], float source_number )
{
    int   chars_used  = 0;    // This will be returned.


    if ( available_chars > 0 )
    {
        // Handle a negative sign.
        if ( source_number < 0 )
        {
            // Make it positive
            source_number = 0 - source_number;
            destination[ 0 ] = '-';
            ++chars_used;
        }

        // Handle rounding
        uint64_t zeros = 1;
        for ( int i = decimal_digits; i > 0; --i )
            zeros *= 10;

        uint64_t source_num = (uint64_t)( ( source_number * (float)zeros ) + 0.5f );

        // Determine sliding divider max position.
        uint64_t  div_amount = zeros;       // Give it a head start
        while ( ( div_amount * 10 ) <= source_num )
            div_amount *= 10;

        // Process the digits
        while ( div_amount > 0 )
        {
            uint64_t whole_number = source_num / div_amount;
            if ( chars_used < (int)available_chars )
            {
                destination[ chars_used ] = '0' + (char)whole_number;
                ++chars_used;

                if ( ( div_amount == zeros ) && ( zeros > 1 ) )
                {
                    destination[ chars_used ] = '.';
                    ++chars_used;
                }
            }
            source_num -= ( whole_number * div_amount );
            div_amount /= 10;
        }


        // Store the zero.
        destination[ chars_used ] = 0;

        // See if a tail was specified.
        size_t tail_len = strlen( tail );

        if ( ( tail_len > 0 ) && ( tail_len + chars_used < available_chars ) )
        {
            for ( size_t i = 0; i <= tail_len; ++i )
                destination[ chars_used + i ] = tail[ i ];
            chars_used += tail_len;
        }
    }

    return chars_used;
}

main()
{
    #define TEMP_BUFFER_SIZE 30
    char temp_buffer[ TEMP_BUFFER_SIZE ];
    char  degrees_c[] = { (char)248, 'C', 0 };
    float  float_temperature = 26.845f;

    int len = snprintf_fp( temp_buffer, TEMP_BUFFER_SIZE, 2, degrees_c, float_temperature );
}
0
DirkDi99ler