在这两种情况下,代码都试图从某种整数类型转换float
为double
..double
转换是因为它是float
传递给可变参数函数的值。
检查您的设置FLT_EVAL_METHOD
,怀疑它的值是 1 或 2(OP 报告2
至少有一个编译器)。这允许编译器评估float
“...操作和常量的范围和精度”大于float
.
您的编译器优化(float)x
直接int
进入double
算术。这是运行时的性能改进。
(float)2147483647
是编译时转换,编译器针对准确性进行了优化,int
因为float
性能double
在这里不是问题。
[Edit2] 有趣的是,C11 规范比 C99 规范更具体,并添加了“除了分配和强制转换......”。这意味着 C99 编译器有时允许int
直接double
转换,而无需先经过float
,并且 C11 被修改为明确不允许跳过强制转换。
由于 C11 正式排除了这种行为,现代编译器不应该这样做,但像 OP 这样的旧编译器可能会这样做——因此是 C11 标准的错误。除非发现某些其他 C99 或 C89 规范另有说明,否则这似乎是允许的编译器行为。
[编辑] 将@Keith Thompson、@tmyklebu、@Matt McNabb 的评论放在一起,编译器即使使用非零值FLT_EVAL_METHOD
,也应该预期会产生2147483648.0...
. 因此,要么编译器优化标志明确地覆盖了正确的行为,要么编译器有一个角落错误。
C99dr §5.2.4.2.2 8 使用浮点操作数的运算值和经过通常算术转换的值以及浮点常量的值被评估为范围和精度可能大于类型要求的格式。评估格式的使用以FLT_EVAL_METHOD的实现定义值为特征:
-1 不确定;
0 仅根据类型的范围和精度评估所有操作和常量;
1 评估类型的运算和常量以及类型float
的double
范围和精度double
,评估long double
运算和常量的范围和类型的精度long double
`;
2 根据类型的范围和精度评估所有操作和常量long double
。
C11dr §5.2.4.2.2 9 除了赋值和强制转换(删除所有额外的范围和精度)之外,由具有浮动操作数的运算符产生的值和经过通常算术转换的值和浮动常量的值被评估为一种格式,其范围并且精度可能大于类型所要求的。评估格式的使用以FLT_EVAL_METHOD的实现定义值为特征
-1(与 C99 相同)
0(同C99)
1(同C99)
2(同C99)