必须在C中声明函数原型吗?

这个问题已经在这里有了答案:

C89,C90或C99中的所有功能都需要原型吗?                                     6个答案

我是C语言的新手(我以前有Java,C#和一些C ++经验)。 在C语言中,是否需要声明一个函数原型,或者如果没有它,代码是否可以编译? 这样做是好的编程习惯吗? 还是仅取决于编译器? (我正在运行Ubuntu 9.10,并使用Code :: Blocks IDE下的GNU C编译器或gcc)

10个解决方案

65 votes

既不需要在“旧” C(包括C89 / 90)中也不在新C(C99)中为C中的函数声明原型。 但是,C89 / 90和C99在函数声明方面有很大的不同。

在C89 / 90中,根本不需要声明函数。 如果在调用时未声明该函数,则编译器从调用中传递的参数类型中隐式“猜测”(推断)声明,并假定返回类型为printf。

例如

int main() {

int i = foo(5);

/* No declaration for `foo`, no prototype for `foo`.

Will work in C89/90. Assumes `int foo(int)` */

return 0;

}

int foo(int i) {

return i;

}

在C99中,必须在调用点之前声明调用的每个函数。 但是,仍然没有必要专门用原型声明它。 非原型声明也将起作用。 这意味着在C99中,“隐式printf”规则不再起作用(在这种情况下,对于推断的函数返回类型),但是如果在没有原型的情况下声明函数,仍可以从参数类型中猜测参数类型。

由于在调用时未声明printf,因此上一个示例无法在C99中编译。 但是,您可以添加非原型声明

int foo(); /* Declares `foo`, but still no prototype */

int main() {

int i = foo(5);

/* No prototype for `foo`, although return type is known.

Will work in C99. Assumes `int foo(int)` */

return 0;

}

...

并以有效的C99代码结束。

尽管如此,在调用函数之前声明一个函数原型总是一个好的习惯。

补充说明:上面我说过,不需要声明函数原型。 实际上,对于某些功能是必需的。 为了在C语言中正确调用可变参数函数(例如printf),必须在调用点之前用原型声明该函数。 否则,行为是不确定的。 这适用于C89 / 90和C99。

AnT answered 2020-01-01T12:29:15Z

62 votes

在ANSI C中(意味着C89或C90),您不必声明函数原型。 但是,最佳实践是使用它们。 该标准允许您不使用它们的唯一原因是为了与非常旧的代码向后兼容。

如果没有原型,则调用函数,编译器将从传递给函数的参数中推断出原型。 如果稍后在同一编译单元中声明该函数,则该函数的签名与编译器的猜测结果不同时,将会出现编译错误。

更糟糕的是,如果函数在另一个编译单元中,则无法获得编译错误,因为如果没有原型,就无法进行检查。 在这种情况下,如果编译器将其弄错,那么如果函数调用在堆栈中压入的类型与函数期望的类型不同,则可能会出现不确定的行为。

惯例是始终在头文件中声明原型,该头文件与包含该函数的源文件同名。

在C99或C11中,在调用任何函数之前,标准C需要在范围内声明函数。 除非您强迫他们这样做,否则许多编译器实际上并没有实施此限制。

user308405 answered 2020-01-01T12:28:22Z

6 votes

如果函数在使用前已定义,则不是必须的。

Drakosha answered 2020-01-01T12:29:36Z

4 votes

这不是必需的,但是不使用原型是一种不好的做法。

使用原型,编译器可以验证您是否正确调用了该函数(使用正确的数量和参数类型)。

如果没有原型,则可能有:

// file1.c

void doit(double d)

{

....

}

int sum(int a, int b, int c)

{

return a + b + c;

}

还有这个:

// file2.c

// In C, this is just a declaration and not a prototype

void doit();

int sum();

int main(int argc, char *argv[])

{

char idea[] = "use prototypes!";

// without the prototype, the compiler will pass a char *

// to a function that expects a double

doit(idea);

// and here without a prototype the compiler allows you to

// call a function that is expecting three argument with just

// one argument (in the calling function, args b and c will be

// random junk)

return sum(argc);

}

R Samuel Klatchko answered 2020-01-01T12:30:09Z

2 votes

在C语言中,如果我们不声明函数原型并使用函数定义,则没有问题,并且如果函数的返回类型为“整数”,则程序将编译并生成输出。 在所有其他情况下,都会出现编译器错误。 原因是,如果我们调用函数而不声明函数原型,则编译器将生成一个原型,该原型返回一个整数,并搜索相似的函数定义。 如果函数原型匹配,则编译成功。 如果返回类型不是整数,则函数原型不匹配,并且会生成错误。 因此,最好在头文件中声明函数原型。

Raviteja answered 2020-01-01T12:30:31Z

1 votes

C允许调用函数,即使它们以前没有被声明过,但是我强烈建议您在使用所有函数之前为所有函数声明一个原型,这样,如果使用错误的参数,编译器可以为您节省时间。

Anders Abel answered 2020-01-01T12:30:51Z

1 votes

您应该将函数声明放在头文件(X.h)中,将定义放在源文件(X.c)中。 然后其他文件可以#include "X.h"并调用该函数。

cpalmer answered 2020-01-01T12:31:12Z

1 votes

根据C99标准,功能原型不是必需的。

zoli2k answered 2020-01-01T12:31:32Z

0 votes

声明一个函数供调用代码进行编译不是绝对必要的。 虽然有一些警告。 假定未声明的函数返回int,并且编译器将首先发出警告:未声明的函数,然后发出有关返回类型和参数类型不匹配的警告。

话虽如此,显然用原型正确声明函数是一种更好的做法。

Nikolai Fetissov answered 2020-01-01T12:31:57Z

-4 votes

选择“选项”菜单,然后选择“编译器| C ++选项”。 在弹出的对话框中,选择“始终CPP”在“使用C ++编译器”选项中。再次选择“选项”菜单,然后选择“环境|编辑'。 确保默认扩展名为“ C”,而不是“ CPP”。

user3725015 answered 2020-01-01T12:32:19Z

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐