STM32L1 snprintf 用法将浮点数转换为字符串

问题描述 投票:0回答:3

我在 STM32 上将 float 转换为 str 时遇到问题, 我有两个简单的函数来打印 Int 和 Float Int 工作正常,但浮点打印导致程序崩溃

void LCD_PrintInt(int value) {
    char str[8];
    sprintf(str, "%d", value);
    LCD_Print(str);
}

void LCD_PrintFloat(float value, uint8_t length) {
    char str[length];
    snprintf(str, length + 1, "%f", value);
    LCD_Print(str);
}

LCD_PrintFloat(99.9, 4); <- crash
LCD_Print("99.9"); <- works fine

我正在使用 STM32CubeIDE 并设置 -u _printf_float 链接器标志 我究竟做错了什么?浮点运算(在STM32上)是正确的方法吗?

floating-point type-conversion stm32
3个回答
0
投票

我做错了什么?

减少1

不要告诉

snprintf()
有比实际可用的空间更多的空间。正如OP所经历的那样,这会导致未定义的行为(UB)。

char str[length];
// snprintf(str, length + 1, "%f", value);  // One too many
snprintf(str, length, "%f", value);

最好使用适合所有人的格式和缓冲区大小

float
。我推荐指数格式,例如:
%a
%g
%e

"%e"
示例:

//                     -   d   .  dddddddd  e   -  E...E \0
#define FLT_TEXT_SIZE (1 + 1 + 1 +    8   + 1 + 1 + 5   + 1)
char str[FLT_TEXT_SIZE];
snprintf(str, sizeof str, "%.*e", FLT_DECIMAL_DIG-1, value);

我怀疑OP的

snprintf()
不能很好地处理缓冲区太小的情况。使用充足的缓冲区。


0
投票

对于“%d”,您至少需要 12 个字符,仅允许 8 个字符。

在“%f”的情况下,你需要 10 个,但你只分配了 4 个,然后你告诉 snprintf 你已经分配了 5 个。

您需要 10 的原因是“99.900000”加上 1 作为空终止符(printf 默认使用 6 位小数)。如果你只想要一位小数,那么你需要使用“%.1f”。

无论你想要多少个地方,你都必须告诉函数有多少字节是真正可用的。当您为空终止符添加 1 时,您还必须将其添加到缓冲区的大小,而不仅仅是函数参数。

[编辑] 我错过了更大的问题是

%f
需要 double 类型的参数,但你传递的是浮点数。如果您使用
-Wall
打开警告,它会告诉您这一点。


0
投票

TL;DR:使用 https://github.com/bofh453/ftoa-fast/ 将浮点数转换为字符串

以newlib为例:snprintf支持打印float。 sniprintf 不支持打印浮点型,但使用少 20 kbyte 的闪存。

我的建议是使用 ftoa() 将浮点数转换为字符串,并使用 sniprintf() 打印字符串。 ftoa 成本约为 1.5 kbyte 闪存;虽然还有很多,但是比 snprintf() 的 20 kbyte 膨胀有了巨大的改进。

还有一个优点:snprintf() 使用 double; ftoa() 使用 float()。特别是在小型 MCU 上,速度差异非常明显。 HTH.

© www.soinside.com 2019 - 2024. All rights reserved.