K&R风格的函数定义问题

14
以下代码是有效的:
int main()
{
   void foo(int);
   foo(3);
   return 0;
}
void foo(a) int a;
{
   printf("In foo\n");
}

但是这个不行:

int main()
{
   void foo(float);
   foo(3.24);
   return 0;
}
void foo(a) float a;
{
   printf("In foo\n");
}
为什么会发生这种情况?

你所说的“工作”是什么意思?是指编译成功还是失败?是指运行正常还是出现问题?具体是什么问题? - Nick
因为第二个例子的语法已经无效了,比我们俩都要年长? - Chris Becke
@Nick:不,它无法编译。这是错误:‘foo’的类型冲突。 - nitzs
1个回答

22

实际上,这是一个非常有趣的问题。

这涉及到C语言的演变方式以及如何向后兼容旧版本。

在两种情况下,您都有一个K&R时代的foo()定义,但先前使用了C99声明(带有原型)。

但在第一种情况下,int作为默认参数实际上就是该参数,因此函数调用是兼容的。

然而,在第二种情况下,K&R定义从K&R时代引入了标准参数提升规则,参数类型实际上是double

但是,在调用点处使用了现代原型,使其成为float。 因此,调用点处的代码可能已经推入了真正的float,这种情况下它与double是不同的类型。

如果所有对foo()的引用都是K&R风格的,我认为你最多会得到一个警告,这就是编译器在那时会做的,而且编译器必须这样做来编译遗留代码。对于过程调用接口来说,这甚至将是一次类型安全的调用,因为所有的浮点数都将被提升为double。(对于内部函数代码不一定如此)


严格来说,我应该说将float参数提升为double的规则被称为“默认参数推广”。此外,我们通常将任何ANSI C的版本称为C99,因为C99标准取代了C89标准。但既然我们特别讨论语言演变,也许我应该指出原型表达式起源于C89。 - DigitalRoss
1
严格来说,自1990年以来,ANSI C已经过时了,因为ANSI C = C89。第一个ISO C标准是C90。当然,ANSI C和C90在功能上是相同的,只是在章节枚举和其他各种外观方面有所不同。 - Lundin
当然,我想提到的是从ANSI C开始的带有原型的修订版,但我想“ISO C”可能是更好的选择。 - DigitalRoss
这个问题很好,但我永远不会写像这样的东西,头文件中总是需要一个原型。 - Mandrake

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