必须在C中声明函数原型?
我对C有点新(我有之前的Java,C#和一些C ++经验)。 在C中,是否有必要声明一个函数原型,或者可以在没有它的情况下编译代码? 这是不是很好的编程习惯? 还是只依赖于编译器? (我正在运行Ubuntu 9.10并使用Code :: Blocks IDE下的GNU C编译器或gcc)
在ANSI C(意思是C89或C90)中,你不必声明一个函数原型; 不过,使用它们是最好的做法。 标准允许您不使用它的唯一原因是为了与旧代码向后兼容。
如果你没有原型,并且你调用一个函数,那么编译器会根据你传递给函数的参数推断一个原型。 如果稍后在同一个编译单元中声明该函数,如果该函数的签名与编译器猜测的不同,则会出现编译错误。
更糟糕的是,如果函数在另一个编译单元中,那么就没有办法获得编译错误,因为没有原型就没有办法检查。 在这种情况下,如果编译器得到错误,如果函数调用在堆栈上压入不同类型的函数,则可能会得到未定义的行为。
约定是始终在与包含该函数的源文件具有相同名称的头文件中声明原型。
在C99或C11中,在您调用任何函数之前,标准C需要在范围内进行函数声明。 除非你强迫他们这样做,否则许多编译器在实践中不会强制执行这个限制。
从来没有要求在C语言中(包括C89 / 90)和新C语言(C99)中声明一个函数的原型 。 但是,C89 / 90和C99在函数声明方面存在显着差异。
在C89 / 90中,根本没有必要声明一个函数。 如果函数没有在调用点声明,那么编译器会根据调用中传递的参数的类型隐式地推断(推断)声明,并假定返回类型是int
。
例如
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中,“implicit int
”规则不再有效(在这种情况下,对于推断的函数返回类型),但是如果函数是在没有原型的情况下声明的,参数类型仍然可以从参数类型中猜出来。
前面的例子不会在C99中编译,因为foo
没有在调用点声明。 但是,您可以添加一个非原型声明
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。
如果该函数在使用之前被定义,则不是必须的。
这不是必需的,但不使用原型是不好的做法。
通过原型,编译器可以验证您是否正确地调用了函数(使用正确的编号和类型的参数)。
没有原型,有可能有这样的:
// 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); }
在C中,如果我们不声明函数原型并使用函数定义,则没有问题,如果函数的返回类型是“整数”,程序将编译并生成输出。 在所有其他情况下,出现编译器错误。 原因是,如果我们调用一个函数而不声明一个函数原型,那么编译器将生成一个返回一个整数的原型,并且它会搜索相似的函数定义。 如果函数原型匹配,则编译成功。 如果返回类型不是整数,那么函数原型不匹配,并产生一个错误。 所以最好在头文件中声明函数原型。
C允许函数被调用,即使它们以前没有被声明过,但是我强烈建议你在使用它们之前为所有的函数声明一个原型,这样如果你使用错误的参数,编译器可以保存你。
您应该将函数声明放在头文件(Xh)中,并将定义放在源文件(Xc)中。 然后其他文件可以#include "Xh"
并调用函数。
根据C99
标准,功能原型不是强制性的。
为调用的代码声明一个函数并不是绝对必要的。 虽然有警告。 未声明的函数被假定为返回int
,编译器将首先发出有关函数未声明的警告,然后关于返回类型和参数类型中的任何不匹配。
话虽如此,很明显,与原型正确地宣布功能是一个更好的做法。
选择“选项”菜单,然后选择“编译器|” C ++选项“。 在弹出的对话框中,在“使用C ++编译器”选项中选择“CPP always”。 再次选择“选项”菜单,然后选择“环境|” 编辑'。 确保默认扩展名是“C”而不是“CPP”。