编译器不喜欢惊喜

当编译器看到这行代码时会发生什么?

  1. printf("Total so far: %.2f\n", add_with_tax(val));
  • 编译器看到了一个不认识的函数调用。

编译器没有报错,而是认为它会在之后的源文件中找到这个函数的详细信息。编译器先记下,随后会在文件中查找函数,很不幸,问题就出在这个地方……

编译器不喜欢惊喜 - 图1

  • 编译器需要知道函数的返回类型。

当然了,编译器现在还不知道函数的返回类型,所以只好假设它返回int

编译器不喜欢惊喜 - 图2

  • 等编译器看到实际的函数,返回了“conflicting types for 'add_with_tax'”错误。

因为编译器认为有两个同名的函数,一个是文件中的函数,一个是编译器假设返回int的那个。

编译器不喜欢惊喜 - 图3

编译器不喜欢惊喜 - 图4脑力风暴

计算机假设函数返回int,但实际返回了float。如果让你设计C语言,你会怎么解决这个问题?

编译器不喜欢惊喜 - 图5

你只要把函数放回正确的位置,在main()调用它之前先定义。

改变函数的顺序,编译器就不用假设未知函数的返回类型,因为这样的假设通常很危险。但如果总是以特定的顺序定义函数,会带来很多后遗症。

调整函数的顺序很痛苦

假设你在代码中添加一个新函数,人人都赞不绝口:

  1. int do_whatever(){...}
  2. float do_something_fantastic(int awesome_level) {...}
  3. int do_stuff() {
  4. do_something_fantastic(11);
  5. }

为了完善程序,你决定在do_whatever()函数中调用do_something_fantastic(),为此必须将do_something_fantastic()函数提前。程序员希望不断改进程序的功能,因此最好有一个两全其美的方法,既不用交换代码的顺序,又能让编译器高兴。

在某些场景中,没有正确的顺序

这种场景有些罕见,但有时你也许想写一些相互递归调用的代码:

编译器不喜欢惊喜 - 图6

如果有两个函数,它们互相调用对方,那么总有一个函数在定义前被调用。

出于以上两个原因,你希望更自由地定义函数,那么该怎么做呢?