C函数调用:理解“隐式int”规则

如果“a function”是单独编译的,那么就不会检测到不匹配,“函数”会返回一个main,它将main视为一个int …根据我们所说的关于声明必须如何匹配定义的内容,这可能会似乎令人惊讶。 可能发生不匹配的原因是如果没有函数原型,则函数通过其在表达式中的第一次出现来隐式声明,例如

sum += "the function"(line); 

如果先前未声明的名称出现在表达式中并且后跟左括号,则上下文将其声明为函数名称,假定该函数返回int,并且不假设其参数。

我事先为这个含糊不清的问题道歉,但这意味着什么?

顺便说一下,这是Brian W. Kernighan和Dennis M. Ritchie的C编程语言书第2版第73页第4.3章。

K&R2涵盖了该语言的1989/1990版本。 当前的ISO C标准于1999年发布,它删除了“隐式整数”规则,并要求对您调用的任何函数进行可见声明。 编译器默认情况下不一定强制执行此操作,但您应该能够请求更严格的警告 – 您肯定应该这样做。 在编写良好的新代码中,规则是无关紧要的(但有必要理解它)。

示例:标准sqrt()函数在声明:

 double sqrt(double); 

如果你编写一个没有必要的#include 的调用:

 double x = 64.0; double y = sqrt(x); 

C90编译器将假设 sqrt返回int – 它将生成将结果从int转换为double 。 结果将是垃圾,或者可能是崩溃。

(您可以自己手动声明sqrt ,但这是错误的解决方案。)

所以不要这样做。 始终包含您呼叫的任何function所需的标头。 如果它返回int (如果你的编译器没有强制执行严格的C99或C11语义,并且如果满足一些其他条件),你可能会调用一个未声明的函数,但是没有充分的理由这样做。

理解“隐式int”规则对于理解旧的或编写得不好的代码的行为仍然有用,但是你不应该在新代码中依赖它。

函数原型最近被引入语言。

在原型之前,编译器会假设传递给每个未知函数的每个参数都应该作为整数传递,并假设返回值也是一个整数。

这适用于少数正确的情况,但意味着人们必须以笨拙的顺序编写程序,以便函数永远不会依赖于与此期望匹配的未知函数。

当原型被引入C89(又名ANSI C或ISO C)时,原型允许编译器确切地知道预期的参数类型以及将返回的结果类型。

强烈建议您对所有新代码使用函数原型; 在处理完全古老的代码库时,原型可能是有害的。 (或者,如果代码必须在ANSI C之前的编译器上编译,那么你可能希望不再使用原型,因此可以在古老的软件上构建gcc是我在很长一段时间内见过的唯一这个地方。)

它只是声明如果编译器遇到调用未知函数的代码,那么它会隐式地将其视为已经看到forms为int unknown();的声明原型int unknown();