使C语言浮点字面量变为float类型(而非double类型)

83

众所周知,在C语言中,浮点字面值(例如1.23)的类型为double。因此,任何涉及它们的计算都会被提升为双精度。

我正在开发一个嵌入式实时系统,其浮点单元仅支持单精度(float)数字。我的所有变量都是float,这种精度已经足够。我根本不需要(也无法承受)double。但每次类似以下代码的操作:

if (x < 2.5) ...

写代码时,如果出现灾难性的情况:程序运行速度会减慢两个数量级。当然,直接的解决方案就是编写

if (x < 2.5f) ...

但这很容易被忽视(直到晚期才难以检测),特别是当一个“配置”值在一个不够有纪律性的(或者刚入门的)开发人员所编辑的单独文件中被 #define 时。

那么,有没有一种方法可以强制编译器将所有(浮点数)字面量都视为 float 类型,就好像加了后缀 f 一样?即使违反规范,我也不在乎。或者其他解决方法?顺便提一下,编译器是 gcc。


32
有一个叫做“-Wdouble-promotion”的选项,它至少会给你警告。结合使用“-Wfloat-conversion”应该可以提供相当好的覆盖率。 - Brett Hale
3
这并不是直接回答你的问题,但编写一个脚本来插入FP字面量中缺失的任何 f 并不难。 - Xophmeister
1
这个有用吗:https://dev59.com/KYHba4cB1Zd3GeqPQ2zT? - Rahul Tripathi
4
一些用于嵌入式系统的编译器将double类型映射为float类型,并仅在选项启用下才启用双精度。我不知道GCC是否存在类似的情况。 - phuclv
3
@BrettHale 的评论值得成为一个合适的回答。我认为在这种情况下获得警告比其他一些编译器选项更加有效,因为它允许程序员编写与标准不兼容的代码。 - user694733
显示剩余7条评论
4个回答

88

-fsingle-precision-constant标志可以使用。即使不精确,它也会导致浮点常数以单精度加载。

注意-这也会在双精度变量的操作中使用单精度常量。


2
谢谢!我不知道有这个标志。这完美地回答了我的问题 - 即使,正如其他人建议的那样,生成警告可能更明智。 - Zeus
2
我会明智地使用这个选项!考虑一个新的开发者,只需键入 x < 2.5,一切都会没问题。他很可能会错过那个能救他一命的特定编译器选项 :-)。当他收到警告信息时(使用 -Wdouble-promotion-Wfloat-conversion),并且您使用 -Werror 将所有警告转换为错误时,他可能不会直接提交代码,并且可能会想要了解更多。但是,仅出于发布质量的考虑,您可能希望安全起见,使用特定选项(-fsingle-precision-constant)进行编译。请注意,这只是一条注释。 - math

57

请使用警告替代: -Wdouble-promotion 警告隐式的浮点数到双精度转换,就像你的例子一样。 -Wfloat-conversion 将会警告可能仍然将双精度赋值给浮点数的情况。

这是比强制将双精度值转换为最接近的浮点值更好的解决方案。您的浮点代码仍然符合标准,如果一个双精度值保存了一个正值,例如小于 FLT_DENORM_MIN(假设是IEEE-754)或大于FLT_MAX,您不会遇到任何问题。


总的来说,你是正确的。但在我的具体情况下,“-fsingle-precision-constant”效果更好。首先,我的GCC版本(4.4.7)根本没有这两个选项。其次,我没有任何棘手的常量(除了NaN),而且所有的计算都必须是“float”类型(这就是整个问题的关键)。最后,提供的芯片库生成了如此多的警告(其中大部分都是显式的!),以至于有用的警告经常被埋在堆中……正如我所说,我对严格的合规性并不是很关心。 - Zeus
2
我也认为仅使用命令开关来隐藏源代码中存在的问题是危险的。要考虑到您的代码可能会在五年后被他人使用,而此时使用的是编译器的新版本,可能没有这个很好的开关。最好的选择是修复源代码中的问题,而不是隐藏它们。至于所有这些警告......在编译生产代码时,应将警告视为错误。 -Werror :-) - Chrissi
强制自己在每个数字字面量的结尾写入“f”并不聪明。 - 12Me21
@12Me21:看一下float fn(float x) { return (x * 1.2); }(1.2f)的汇编输出-表达式被强制评估为double,然后转换回float。这不是“聪明”的问题。 - Brett Hale
哦,我的意思是,我觉得-fsingle-precision-constant在这里是更好的解决方案。同样的结果,更少的努力。 - 12Me21
@12Me21,强制自己在每个整数后面写上“.0”以确保它是浮点数而不是整数并没有什么聪明之处。这只是ANSI-C的工作方式,反对它有点像在与风车斗争。如果我可以写“.0”,那么接受“.0f”也不需要更多的努力。 - Kenn Sebesta

2
您可以在使用常量的任何地方将其转换为(float),优化器应该会做好工作。这是一种便携式的解决方案。
#define LIMIT 2.5

if (x < (float)LIMIT) ...

或者将它们转换为定义中的形式,例如 #define foo ((float) 1.234)。 - CuriousRabbit
3
@CuriousRabbit:这并没有解决“缺乏纪律(或者只是新手)开发者”的问题。 - user1196549

1
"-Wunsuffixed-float-constants标志也可以使用,可能与上面接受的答案中的一些其他选项组合使用。但是,这可能无法捕获系统头文件中的未加后缀的常量。需要使用-Wsystem-headers来捕获那些常量。可能会生成很多警告..."

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