31

伙计们,我想知道float变量是否可以在sprintf()函数中使用。

就像,如果我们写:

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

其中adc_read是一个整数变量,它将存储字符串

"adc_read = 1023 \n"

str(假设 adc_read = 1023

如何使用浮点变量代替整数?

4

13 回答 13

58

由于您使用的是嵌入式平台,因此您很可能没有来自printf()-style 函数的全部功能。

假设你有浮动(对于嵌入式的东西仍然不一定是给定的),你可以用类似的东西来模拟它:

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 位有符号整数,您只能使用四位数字(9,999 是可以表示的最大 10 次幂)。

但是,有一些方法可以通过进一步处理小数部分来处理这个问题,每次将其移动四位小数(并使用/减去整数部分),直到获得所需的精度。


更新:

您提到的最后一点是您avr-gcc在对其他答案之一的回应中使用的。我发现以下网页似乎描述了您在此处%fprintf()陈述中需要执行的操作。

正如我最初怀疑的那样,您需要做一些额外的工作才能获得浮点支持。这是因为嵌入式东西很少需要浮点(至少我做过的东西都没有)。它涉及在您的 makefile 中设置额外的参数并与额外的库链接。

但是,由于需要处理通用输出格式,这可能会大大增加您的代码大小。如果您可以将浮点输出限制为小数点后 4 位或更少,我建议将我的代码变成一个函数并使用它——它可能占用更少的空间。

万一该链接消失了,您要做的就是确保您的 gcc 命令具有"-Wl,-u,vfprintf -lprintf_flt -lm“。这意味着:

  • 强制 vfprintf 最初是未定义的(以便链接器必须解决它)。
  • printf()指定用于搜索的浮点库。
  • 指定用于搜索的数学库。
于 2009-05-25T09:13:56.967 回答
6

这样的事情不是很容易吗:

#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);
于 2012-05-24T21:56:50.007 回答
2

使用%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

于 2009-05-25T08:51:31.007 回答
2

是的,当然,花车并没有什么特别之处。您可以使用 printf() 中用于浮点数和任何其他数据类型的格式字符串。

编辑 我尝试了这个示例代码:

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

输出为:测试=0.61

于 2009-05-25T08:53:32.297 回答
2

是的你可以。但是,这取决于您链接的 C 库,您需要了解后果。

由于您正在为嵌入式应用程序编程,请意识到浮点支持已针对许多嵌入式体系结构进行了仿真。在这种浮点支持中进行编译最终会显着增加可执行文件的大小。

于 2009-05-25T09:00:53.187 回答
1

不要指望 sprintf(或任何其他带有可变参数的函数)会自动转换任何东西。编译器不会尝试读取格式字符串并为您进行转换;在运行时,sp​​rintf 没有可用的元信息来确定堆栈上的内容;它只是弹出字节并将它们解释为格式字符串给定的。sprintf(myvar, "%0", 0); 立即出现段错误。

所以:格式字符串和其他参数必须匹配!

于 2009-05-25T09:01:33.763 回答
0

是的,没有。尽管其他一些回复说了什么,但 C 编译器需要sprintf()和所有其他可变参数函数执行转换,如下所示:

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

(以及上述整数类型的有符号/无符号变体)

它这样做正是因为sprintf()(和其他print()-family 功能)没有它将无法使用。(当然,它们实际上是非常不可用的。)

但是您不能假设任何其他转换,并且您的代码将具有未定义的行为 - 阅读:崩溃!- 如果你这样做。

于 2009-05-25T09:15:58.960 回答
0

查看适用于您平台的 sprintf 的文档。它通常是 %f 或 %e。您唯一能找到明确答案的地方是文档……如果没有文档,您所能做的就是联系供应商。

它是什么平台?有人可能已经知道文档在哪里...... :)

于 2009-05-25T10:35:16.367 回答
0

不要这样做;C/C++ 中的整数总是向下舍入,因此不需要使用 floor 函数。

char str[100]; 
int d1 = value;

更好用

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

然后你不会得到整数部分的四舍五入(68.99999999999999999 变成 69.00..)。很难避免使用 68.09999847 而不是 68.1 - 任何浮点格式都具有有限的精度。

于 2009-12-31T04:06:02.803 回答
0

%g可以这样做:

#include <stdio.h>
int main() {
  float w = 234.567;
  char x[__SIZEOF_FLOAT__];
  sprintf(x, "%g", w);
  puts(x);
}
于 2016-01-12T04:49:50.127 回答
0

许多嵌入式系统具有不处理浮点数的有限 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 );
}
于 2019-03-15T16:29:28.517 回答
0

类似于上面的paxdiablo。此代码插入到更广泛的应用程序中,可与 STM32 NUCLEO-F446RE 一起正常工作。

#include <stdio.h>
#include <math.h>
#include <string.h>
void IntegFract(char *pcIntegStr, char *pcFractStr, double dbValue, int iPrecis);

main()
{
   char acIntegStr[9], acFractStr[9], char counter_buff[30];
   double seconds_passed = 123.0567;
   IntegFract(acIntegStr, acFractStr, seconds_passed, 3);
   sprintf(counter_buff, "Time: %s.%s Sec", acIntegStr, acFractStr);
}

void IntegFract(char *pcIntegStr, char *pcFractStr, double dbValue, int 
iPrecis)
{
    int iIntegValue = dbValue;
    int iFractValue = (dbValue - iIntegValue) * pow(10, iPrecis);
    itoa(iIntegValue, pcIntegStr, 10);
    itoa(iFractValue, pcFractStr, 10);
    size_t length = strlen(pcFractStr);
    char acTemp[9] = "";
    while (length < iPrecis)
    {
        strcat(acTemp, "0");
        length++;
    }
    strcat(acTemp, pcFractStr);
    strcpy(pcFractStr, acTemp);
}

counter_buff 将包含 123.056 。

于 2020-01-01T15:37:27.737 回答
-2

是的,使用 %f

于 2009-05-25T08:51:47.057 回答