为什么我们需要功能原型?

时间:2017-03-17 22:45:57

标签: c function function-prototypes

我正在学习C,我的书正在解释如何“原型化一个函数”,所以我们可以在定义它之前使用它。

关键是我无法想象在定义它之前需要使用函数的情况,为什么我们不能在开始时定义它?

您能否提供一个示例,其中对于函数原型(如果存在)是非常必要的?

3 个答案:

答案 0 :(得分:1)

考虑以下计划:

#include <stdio.h>

void add(int, int);

int main() {
    add(5, 3);
    return 0;
}

void add(int a, int b) {
    printf("%d", a+b);
}

在这里,当您从add(5, 3)调用main()时,编译器知道add()是什么 - 它所采用的参数和返回类型,这要归功于void add(int, int)中的语句{第3行。如果这个语句被注释掉,那么编译器将不知道add()是什么并且会给你一个错误。因此,第3行告诉编译器您之后已经定义了函数add(),这使得它完全有资​​格在main()中使用。或者,如果您在 add()之前编写main()函数,则编译器会在调用它时知道add()是什么;所以在这种情况下不需要函数原型。

希望这很有用。

答案 1 :(得分:1)

一个用例是当您希望将函数指针指向另一个源文件中定义的函数。 (或用 asm 手写)。获取函数指针总是需要通过定义或原型提前声明该函数。

C89(及更早版本)允许隐式声明函数(即使编译单元中没有定义或原型,也可以使用它们(这个 .c + 任何你 #include)。

所以你可以在 C89(或 with a warning from most compilers in C99 / C11 mode)中自己编译一个文件

int foo() {
    return bar( 123 );   /* implicit declaration of  int bar()  */
}

但是你不能使用 &bar 作为函数指针

/* int bar(int);      necessary if you haven't defined  int bar(int x) { ... } */
void *take_fptr() {
     return &bar;    // error: 'bar' undeclared   from GCC
}

您还可以构建需要声明才能正确传递参数的情况,例如如果您希望函数采用 float 参数,则需要通过定义或原型对其进行声明。 ISO C 标准中的“默认参数提升”将在将 arg 传递给非原型函数时将 float 提升为 double,或者将参数传递给 printf 等可变参数函数的 ... 部分。< /p>

(这就是为什么 %f 打印双精度数而不是浮点数的原因,以及为什么 %lf 如果完全支持它也是双精度数。也是为什么像 putchar(int) 这样的函数将它们的 char arg 作为一个 int:窄整数类型的默认提升到 int。C 标准库的某些部分可以追溯到非常早期的 C,在语言支持原型之前!)

或者例如,如果您的函数需要一个 long long,但调用者写的是 bar( 123 ),则调用者只会推断出 int,它的传递方式可能与 {{1} }}。但是您可以通过编写 long longbar( 123LL )

来解决此问题

或者如果返回类型不是bar( (long long)123 )(或int),那么您还需要编译器通过声明来了解该函数。假定隐式声明的函数返回 void。根据调用约定和架构,对于 int 返回类型,或者在某些机器上,甚至对于 short,您可能会避开它,例如在 char*intptr_t 的 32 位机器上。 (早期的 C 依赖于此。)

但总的来说,例如在具有 64 位指针的机器上,implicit-int return 不起作用。它也不适用于 int 返回值或 double

答案 2 :(得分:-1)

当时可能不知道该功能的定义。想象一个调用malloc来分配内存的程序。在编译时,没有人知道程序将在运行时使用什么分配器。那你怎么定义这个功能呢?