web-dev-qa-db-ja.com

埋め込みCでsprintf()でフロートを使用する

皆さん、float変数をsprintf()関数で使用できるかどうか知りたいです。

たとえば、次のように書くと:

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

adc_readは整数変数で、文字列を格納します

"adc_read = 1023 \n"

stradc_read = 1023と仮定)

整数の代わりにフロート変数を使用するにはどうすればよいですか?

26
aditya

組み込みプラットフォームを使用しているため、printf()スタイルの機能のすべての機能を使用できない可能性があります。

フロートがまったくあると仮定すると(まだ埋め込みのものに与えられているとは限りません)、次のようなものでエミュレートできます:

_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);
_

整数のサイズに基づいて、小数点以下の文字数を制限する必要があります。たとえば、16ビットの符号付き整数では、4桁に制限されます(9,999は表現可能な最大の10のべき乗1です)。

ただし、小数部分をさらに処理し、必要な精度が得られるまで毎回小数部分を4桁ずつシフト(および整数部分を使用/減算)することで、これを処理する方法があります。


更新:

最後のポイントとして、他の回答の1つに対する応答で_avr-gcc_を使用していると述べました。 printf()ステートメントで_%f_を使用するために必要なことを説明していると思われる次のWebページを見つけました here

私が当初疑っていたように、浮動小数点サポートを得るには、いくつかの追加の作業が必要です。これは、埋め込まれたものが浮動小数点を必要とすることはめったにないからです(少なくとも、これまでに行ったことのないもの)。メイクファイルに追加のパラメーターを設定し、追加のライブラリとリンクする必要があります。

ただし、一般的な出力形式を処理する必要があるため、コードサイズがかなり大きくなる可能性があります。フロート出力を小数点以下4桁以下に制限できる場合は、コードを関数に変換し、それを使用することをお勧めします-使用するスペースがはるかに少なくなります。

そのリンクが消えた場合、あなたがしなければならないことは、gccコマンドに_"-Wl,-u,vfprintf -lprintf_flt -lm_ "があることを確認することです。これは次のように変換されます:

  • vfprintfを最初は未定義にする(リンカーが解決する必要があるように)。
  • 検索用の浮動小数点printf()ライブラリを指定します。
  • 検索用の数学ライブラリを指定します。
47
paxdiablo

このようなものは本当に簡単ではありません:

#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

はい、できます。ただし、リンク先のCライブラリに依存するため、結果に注意する必要があります。

組み込みアプリケーション用にプログラミングしているので、多くの組み込みアーキテクチャで浮動小数点サポートがエミュレートされることを理解してください。この浮動小数点サポートをコンパイルすると、実行可能ファイルのサイズが大幅に増加します。

2
sybreon

Sprintf(または可変引数を持つ他の関数)が自動的にキャストすることを期待しないでください。コンパイラは、フォーマット文字列を読み取ってキャストを試みません。実行時に、sprintfには、スタック上にあるものを判断するためのメタ情報がありません。バイトをポップし、フォーマット文字列で指定されたとおりに解釈します。 sprintf(myvar、 "%0"、0);すぐにセグメンテーション違反。

そのため、フォーマット文字列と他の引数は一致する必要があります!

1

はいといいえ。他のいくつかの回答が述べているにもかかわらず、Cコンパイラissprintf()および他のすべての可変機能関数の変換を実行するために必要です。次のとおりです。

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

(および上記の整数型の符号付き/符号なしバリアント)

sprintf()(および他のprint()- family関数)は、それなしでは使用できないため、これを正確に行います。 (もちろん、 これらはそのままでは使用できません 。)

しかし、他の変換を想定することはできず、コードの動作は未定義になります-read:crash! -あなたがそれをするなら。

0
dcw

これをしないでください。 C/C++の整数は常に切り捨てられるため、floor関数を使用する必要はありません。

char str[100]; 
int d1 = value;

使いやすい

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

整数部分の切り上げは行われません(68.9999999999999999は69.00になります)。 68.1の代わりに68.09999847を避けるのは困難です-浮動小数点形式の精度は限られています。

0
setltd

%gこれを行うことができます:

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

使用 %f修飾子:

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

例えば:

#include <stdio.h>

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

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

これをもたらします:

x = 2.500000

0
Nathan Fellman

はい、もちろん、フロートには特別なものはありません。 floatおよびその他のデータ型にprintf()で使用するのと同じ形式の文字列を使用できます。

[〜#〜] edit [〜#〜]私はこのサンプルコードを試しました:

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

出力:Test = 0.61

0
Naveen

プラットフォームのsprintfのドキュメントをご覧ください。通常は%fまたは%eです。明確な答えを見つけることができる唯一の場所は文書です...文書化されていない場合は、サプライヤーに連絡してください。

どのプラットフォームですか?誰かがドキュメントの場所をすでに知っているかもしれません... :)

0
jheriko

多くの組み込みシステムには、フロートを処理しないsnprintf関数が制限されています。私はこれを書きました、そしてそれはかなり効率的にトリックをします。 64ビットの符号なし整数を使用して大きなフロートを処理できるようにしたので、それらを16ビットまたは限られたリソースで必要なものに減らしてください。

#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