繁体   English   中英

function 定义中浮动的奇怪行为。 声明-定义不匹配,但它有效,如何?

[英]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,请始终使用原型(同样适用于charshort 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM