[英]Strange behavior of float in function definition. And declaration-definition mismatch, yet it works, how?
即使声明中 function 的签名与定义不匹配,以下代码如何工作? function 声明的参数列表为空,但定义只有一个参数。 为什么编译器不报错?
#include <stdio.h>
double f(); //function declaration
int main(void)
{
printf("%f\n", f(100.0));
}
double f(double param) //function definition
{
return 5 * param ;
}
它编译并运行良好( ideone )。
但是,如果我将定义中的参数类型从double
更改为float
,则会出现以下错误( ideone ):
prog.c:7:错误:“f”的类型冲突
prog.c:8:注意:具有默认提升的参数类型与空参数名称列表声明不匹配
prog.c:2: 错误: 'f' 的先前声明在这里
float
有什么问题? 为什么它会给出错误float
而不是double
?
这是声明和定义对的列表,以及哪些对有效,哪些无效:
作品( ideone )
double f(); //declaration double f(double param); //definition
不起作用( ideone )
double f(); //declaration double f(float param); //definition
作品( ideone )
float f(); //declaration float f(double param); //definition
不起作用( ideone )
float f(); //declaration float f(float param); //definition
所以看起来,只要参数类型是float
,它就不起作用!
所以我基本上有两个问题:
float
时它不起作用?我尝试理解第 §6.5.2.2 (C99) 部分,但该语言非常神秘,以至于我无法清楚地理解。 我什至不知道我是否阅读了正确的部分。 所以请用简单的话来解释这些行为。
您认为声明与定义不匹配的假设是不正确的。 (在 C++ 中会出现这种情况,但在 C 中不会出现这种情况)。 在 C 语言中
double f();
声明没有完全声明function,即没有介绍原型。 它只宣布 function f
存在并且它的返回类型是double
的事实。 它完全没有说明f
s arguments 的数量和类型。 arguments 绝对可以是任何东西。 从这个意义上说,您示例中的声明确实与定义相匹配(即,它与定义不矛盾,这对于 C 编译器来说已经足够了)。
如果你真的想要声明一个没有 arguments 的 function,你必须在参数列表中指定一个明确的void
double f(void);
这确实与定义相矛盾。 你原来拥有的东西没有。
当您调用已用空参数列表()
声明的 function 时,您有责任提供正确类型的正确数量的 arguments。 如果您犯了错误,则行为是未定义的。 这是当您将实际参数类型更改为float
时编译器会警告您的内容。
您对声明和定义的“对”的分析并不完全正确。 这是被误导的。 这与声明和定义无关。 这实际上是关于定义和调用function 的方式。 在原始情况下,您使用double
参数调用它,并且使用double
参数声明 function。 所以一切都是匹配的。 但是当你用一个double
参数调用它并用一个float
参数声明它时,你会得到一个不匹配的结果。
另请注意,当 function 被声明为没有原型时, float
arguments 始终提升为double
arguments。 因此,无法将float
参数传递给使用()
参数列表声明的 function。 如果您想要float
arguments,请始终使用原型(同样适用于char
和short
arguments)。
C 允许 function 声明为空。 从 C99 6.7.5.3/14 开始:
function 声明符中的空列表不是该 function 定义的一部分,它指定不提供有关参数数量或类型的信息。
这与void
参数列表不同,后者明确指出 function 没有 arguments。 从 6.7.5.3/10 开始:
void
类型的未命名参数作为列表中的唯一项的特殊情况指定 function 没有参数。
另请注意,如果未声明类型,则您的声明不是原型。 从 6.2.1/2 开始:
function 原型是声明其参数类型的 function 的声明。
第二个问题确实和C99 6.5.2.2/6有关:
如果表示被调用的 function 的表达式具有不包含原型的类型,则对每个参数执行 integer 提升,并将具有
float
类型的 arguments 提升为double
精度。
因此,在您的情况下,每当调用 function 时, float
都会被提升为double
,并且在调用堆栈(或eax
或其他任何东西)中放置一个double
。 但是,当然,如果您的 function定义采用float
,它将从调用堆栈中读取一个float
,这将导致二进制不兼容。 编译器知道这一点,因此会出现错误消息。
在 C 中,声明中的空参数列表意味着 function 可以与 0 个或多个 arguments 一起调用。
此类函数在使用浮点数调用时,会隐式将其视为double
。 (和整数参数为int
。)
所以当你调用 foo(100.0) 时,你是用一个 double 调用它。 如果您尝试使用浮点数调用它,则参数将在调用时转换为双精度。
如果您将 function 定义为浮点数,这将不起作用,因为双精度数和浮点数的传递方式不同。 因此,编译器很有帮助地给你一个错误。
很高兴你在 2011 年而不是 1985 年犯了这个错误,因为编译器过去非常愚蠢,这是一个难以追踪的噩梦般的错误。
底线:在现代 C 中声明具有空参数列表的函数是非常糟糕的风格。 正确声明 function,如果要被多个翻译单元引用,则将声明放入 header 文件中。
[编辑]
正如评论中详细指出的那样,如果您真的想声明 function 为零 arguments,请声明它为void
。 (或切换到 C++...)
在 C 中,一个空的 function 声明就像在 C++ 中使用...
也就是说,它匹配任何数量和类型的 arguments。 使用float
而不是double
的问题是float
会自动提升为double
。 当调用f(...)
(借用 C++ 表示法)时,它不知道预期的类型,所以它被提升为 double。 稍后,当您重新声明f
以采用float
参数时,这与 f 的隐式声明为f
f(double)
冲突。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.