如果单独编译“一个函数”,则不会检测到不匹配,“该函数”将返回一个double,main将其视为int ...根据我们所说的声明必须与定义相匹配,这可能看起来令人惊讶。可能发生不匹配的原因是,如果没有函数原型,则函数将在表达式中首次出现时隐式声明,例如
sum += "the function"(line);
如果表达式中出现了一个之前没有声明过的名称,并且后跟一个左括号,则上下文将其声明为函数名,假定该函数返回一个int,并且不假定其参数。
我先为这个模棱两可的问题道歉,但这是什么意思?
顺便说一下,这是Brian W. Kernighan和Dennis M.里奇的C编程语言书第2版的第73页第4.3章。
3条答案
按热度按时间zvokhttg1#
K&R2涵盖了该语言的1989/1990版本。(1999,2011等),放弃了“隐式int”规则,并要求调用的任何函数都有一个可见的声明。默认情况下,编译器不一定强制执行这一点,但你应该能够请求更严格的警告--你绝对应该这样做。在编写良好的新代码中,规则是不相关的(但有必要理解它)。
例如:标准
sqrt()
函数在<math.h>
中声明:如果你写了一个调用 * 没有 * 所需的
#include <math.h>
:一个C90编译器将 * 假定 *
sqrt
返回int
--它将生成代码将结果从int
转换为double
。结果将是垃圾,或者可能是崩溃。(You* 可以 * 自己手动声明
sqrt
,但这是错误的解决方案。所以不要这样做。总是包含你调用的任何函数所需要的任何头文件。如果它确实返回
int
(如果你的编译器没有强制执行严格的C99或C11语义,并且如果满足一些其他条件),你可能会调用一个未声明的函数,但没有很好的理由这样做。理解“隐式int”规则对于理解旧代码或编写不好的代码的行为仍然很有用,但在新代码中永远不应该依赖它。
ttisahbt2#
函数原型很晚才被引入到语言中。
在原型之前,编译器会假设传递给每个未知函数的每个参数都应该作为整数传递,并假设返回值也是整数。
这在少数情况下是正确的,但这意味着人们必须以一种尴尬的顺序编写程序,以便函数永远不会依赖于不符合预期的未知函数。
当原型被引入C89(也称为ANSI C或ISO C)时,原型允许编译器确切地知道期望什么类型的参数以及将返回什么类型的结果。
强烈建议您对所有新代码使用函数原型;当在一个完全旧的代码库上工作时,原型可能是有害的。(或者,如果代码必须在ANSI C之前的编译器上编译,那么你可能希望离开原型,这样它就可以在旧的软件上构建。
gcc
是我在很长一段时间内唯一看到的地方。)gab6jxml3#
它只是说明,如果编译器遇到调用未知函数的代码,那么它会隐式地将其视为已经看到
int unknown();
形式的声明原型