2

为什么函数需要事先在 C 中声明?

4

6 回答 6

1

这样编译器就可以在调用函数时检测到类型错误。当然有办法解决这个问题,但这是他们选择的方式。

于 2009-11-25T19:20:26.733 回答
1

现代 C 语言中的函数需要预先声明,原因有两个:1) 告诉编译器特定名称是函数的名称(而不是其他名称),2) 告诉编译器的确切返回类型函数,以便编译器可以正确处理该返回。

在 C 中,可以使用或不使用原型来声明函数。原型声明为编译器提供了更多信息。它包括有关函数参数(如果有)的数量和类型的信息,从而帮助编译器为函数调用正确准备参数。

在 C 语言的 C89/90 版本中,函数不必事先声明,这导致编译器在调用点对函数做出假设。不用说,在许多情况下,这被证明是危险的。

于 2009-11-25T19:37:21.330 回答
0

这样一次性编译器就知道要为每个参数传递多少字节。

考虑:

f(12345);

int f(char input)
{
   printf("%c",input);
}

如果没有原型,编译器将假定f接受整数,并将sizeof(int)字节发送到函数(通过堆栈或寄存器,具体取决于平台)。但是该函数只会查看 1 个字节,这将给出错误的结果。

于 2009-11-25T19:28:02.890 回答
0

因为旧的编译器速度和内存有限,所以他们希望一切都可以一次完成(只需从上到下读取文件,一切都可以理解)。

现代设计的编译器可以向上、向下查找函数,甚至在尚未声明的不同文件中。

于 2009-11-25T19:32:27.427 回答
0

基本上,你不会......

如果您尚未声明它,许多编译器会假设您正在调用 int Function() 签名。链接器......嗯......可能不会吃那个。

如果声明的函数的签名与调用语句不匹配,编译器会介意,但在第二步出现问题: - 为参数传递和返回值预编码进行编码

后者实际上必须为每个调用确定。正是在第二个代码生成步骤中,C编译器才真正错过了声明(这就是函数签名的原因)。然后链接器还需要将函数的符号调用转换为实际的......呃......调用。但是如果函数存在于“某处”(去调查extern修饰符),链接器将不会成为显示停止器。

所有这一切的例外是函数指针机制,您可以在其中告诉编译器和链接器预期的签名,但调用本身不是由编译器决定的,链接器也没有“硬编码”调用......检查出来。

于 2009-11-25T19:36:25.513 回答
0

我确信这不是唯一的原因,但是当您只知道函数的声明(例如从头文件中)时,您可以通过调用其他函数来编译文件。这是可能的,无需重新编译函数本身的定义(可能在另一个文件中)。但是为了验证函数被正确调用,编译器必须知道它的声明。然后链接器会处理剩下的事情。

这里有一个小例子

主.c:

#include "function.h"

int main(){
    function();
    return 0;
}

函数.h:

#ifndef FUNCTION_H
#define FUNCTION_H

void function();

#endif

函数.c:

#include "function.h"

void function(){}

我正在使用 gcc 像这样编译:

gcc function.c -c 

这将产生一个目标文件function.o。现在,当我想编译我的 main 函数时,我不必再编译我的 function.c 文件,我只需要知道头文件和目标文件中的声明:

gcc main.c function.o -o test

现在,目标文件将链接到我的程序中而无需重新编译。

于 2009-11-25T20:04:00.853 回答