有没有一种printf格式说明符只能接受float而不是double?

8
当我使用类型为float的参数并使用“%f”说明符进行snprintf时,我遇到了MISRA类型错误。
据我的研究,MISRA是正确的,因为“%f”需要double类型。 是否有浮点说明符或修饰符可以使用float类型参数而不是double类型? 我正在开发嵌入式系统,并不想将32位浮点数转换为64位double,只是为了满足snprintf函数。该代码打印到调试/控制台端口,这是唯一进行转换的地方。
以下是需要代码示例的部分:
// This section is for those C++ purists and it fulfills the C++ tag.
#if __cplusplus
#include <cstdio>
#else
#include <stdio.h>
#endif

#define BUFFER_SIZE (128U)

int main(void)
{
    char buffer[BUFFER_SIZE];
    float my_float = 1.234F;

    // The compiler will promote the single precision "my_float"
    //   to double precision before passing to snprintf.
    (void)snprintf(buffer, BUFFER_SIZE, "%10.4f", my_float);
    puts(buffer);
    return 0;
}

我在Stack Overflow和网络上的所有研究都是关于打印浮点数值的,而不是关于哪些说明符需要float参数以避免发生到double的提升。

我正在使用IAR嵌入式Workbench编译器用于ARM7TDMI处理器。


MISRA-C:2004中没有与*printf函数的类型说明符相关的规则。唯一适用的MISRA规则是20.9“stdio.h不得在生产代码中使用”。因此,似乎您的编译器给出了错误的错误提示,它应该告诉您“错误:使用了禁止的函数”或类似的内容。 - Lundin
还有16.1条规定:“函数不得使用可变数量的参数进行定义”,这将有效禁止stdio.h的使用。 - Lundin
为什么printf()会将float提升为double? - phuclv
一般来说,嵌入式处理器编译器通常具有覆盖标准语言行为并在程序中的任何地方使用浮点表示法以消除问题转换的选项。我不知道您使用的特定编译器是否具有此功能。 - doug65536
4个回答

21
不会,因为printf及其相关函数是可变参数函数,所以float参数会自动转换为double作为默认参数提升的一部分(请参阅C99标准的6.5.2.2节)。
我不确定为什么这会触发MISRA警告,我无法想到任何可能存在危险的方式。

1
有没有办法阻止或停止默认参数提升? - Thomas Matthews
1
@ThomasMatthews:不行。不幸的是,您最好制作自己的 sprintf 版本并具有浮点说明符,然后将该 float 作为 char* 传递,然后在打印函数内重新解释它。 - GManNickG
1
@ThomasMatthews:考虑到从float转换为double实际涉及的内容,即使在没有硬件浮点支持的平台上,转换也可能是微不足道的。 - Oliver Charlesworth
3
只要函数不是变参函数,你可以将一个float参数传递给函数而不会自动提升为double。你可以编写自己的函数,接受一个float参数,并执行 snprintf(buffer, BUFFER_SIZE, "%10.4f", my_float); 的功能。我严重怀疑性能会显著提高,但你可以尝试并自行测量。 - Keith Thompson
1
@ThomasMatthews,你的静态分析器有问题,它不应该让你使用stdio.h或可变参数列表。在符合MISRA-C规范的程序中,关于类型说明符是没有规定的,因为stdio.h永远不能被用于这样的程序中。IAR MISRA-checker以荒谬的错误而闻名,但几乎所有市场上的MISRA checker都是如此。 - Lundin
显示剩余4条评论

9

没有,因为在通过变量参数列表传递时,标准促销将每个float参数转换为double


5

正确的MISRA-C:2004合规性分析应该给出以下结果:

  • 违反1.1,代码不符合ISO 9899:1990(C++代码,C99代码)。
  • 违反2.2,使用//注释。
  • 违反16.1,使用可变参数函数。
  • 违反20.9,使用stdio.h。

如果您得到的错误与上述错误不同,则您的静态分析工具可能存在问题。

我已经手动分析过,并使用LDRA Testbed 7.6.0进行了分析。


如果使用 stdio.h 是一种违规行为,那么将 double 转换为字符串似乎很困难。 - chux - Reinstate Monica
1
@chux 是的。你必须使用其他库或自己编写。另一方面,自定义函数比sprintf快得多。或者你可以违反MISRA并使用stdio.h。尽管根据我的经验,许多使用float的程序实际上应该重写为使用普通整数。初学者往往根据输出是否需要小数点来决定使用float,这当然是无稽之谈。只有需要更高级数学的程序才需要float。 - Lundin

0

在 printf 函数中无法指定 float 而不是 double,因为会自动提升类型。但我认为你可以从以下代码进行更改:

(void)snprintf(buffer, BUFFER_SIZE, "%10.4f", my_float);

to:

(void)snprintf(buffer, BUFFER_SIZE, "%10.4f", (double)my_float);

并获得正确的结果


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接