C89,C90或C99的所有function都需要原型吗?

为了达到真正的标准,C语言中的所有函数(main函数除外)都有一个原型,即使它们只在被定义在同一个翻译单元之后才被使用?

这取决于你的意思是“真正符合标准”。 但是,简短的回答是“确保所有function在使用前都有一个原型”是一个好主意。

更合适的答案指出,如果函数接受可变参数(特别是printf()系列函数),那么原型必须严格符合标准。 C89(来自ANSI)和C90(来自ISO;与C89除了部分编号相同)都是如此。 不过除了'varargs'函数外,返回一个int函数不一定要被声明,而返回int以外的函数的函数也需要一个声明来显示返回types,但是不需要参数列表的原型。

但是请注意,如果函数在没有原型的情况下接受了“正常升级”的参数(例如,一个函数接受一个char或者short ,两个都转换为int ;更严重的是,函数采用float而不是double ),那么需要原型。 这个标准是松散的,允许旧的C代码在标准的符合性编译器下编译; 旧的代码没有写出来担心确保函数在使用之前被声明 – 根据定义,较旧的代码没有使用原型,因为直到有一个标准,它们在C中不可用。

C99不允许使用“implicit int”…这意味着两个古怪的案例,比如“ static a; '(默认是一个int )以及隐式函数声明。 在ISO / IEC 9899:1999的前言中提到了这些标准(以及其他约50个主要变更),该标准将该标准与以前的版本进行了比较:

  • 删除隐式int
  • 去除隐式函数声明

在ISO / IEC 9899:1990,§6.3.2.2 函数调用中声明:

如果函数调用中的括号括起来的参数列表之前的expression式仅由一个标识符组成,并且对于该标识符没有可见的声明,则该标识符被隐含地声明,就像在包含该函数调用的最内部的块中那样声明:

 extern int identifier(); 

出现了。 38

38也就是说,一个块范围的标识符被声明为具有不带参数信息的types函数的外部链接并返回一个int 。 如果实际上它没有被定义为具有types“返回int函数”,则行为是未定义的。

1999年的标准中缺less这一段。 我还没有(跟踪)允许static a;语言变化static a; 在C90中,并且在C99中禁止它(需要static int a; )。

请注意,如果一个函数是静态的,那么它可以在使用之前被定义,并且不需要在声明之前。 GCC可以被劝说,如果一个非静态函数被定义而没有在它之前的声明( -Wmissing-prototypes )。

不,function并不总是需要一个原型。 唯一的要求就是在使用它之前要先声明一个函数。 有两种方法来声明一个函数:编写一个原型,或者编写函数本身(称为“定义”)。定义总是一个声明,但并不是所有的声明都是定义。

原型是一个函数声明,用于指定函数参数的types。

Pre-ANSI C(Kernighan&Ritchie的“The C Programming Language”1978年第一版所描述的语言)没有原型; 函数声明不可能描述参数的数量或types。 这是由调用者传递正确的数量和types的参数。

ANSI C引入了“原型”,声明了指定参数types(从早期的C ++借用的一个特性)。

从C89 / C90开始(ANSI和ISO标准描述相同的语言),调用没有明显声明的函数是合法的。 提供了一个隐式声明。 如果隐式声明与实际定义不兼容(比如说调用sqrt("foo") ,那么这个行为是不确定的。这个隐式声明和非原型声明都不能和可变参数兼容,所以调用可变参数函数(如printfscanf )必须具有可见的原型。

C99丢弃隐式声明。 任何不带可见声明的函数调用都会违反约束条件,需要编译器诊断。 但是这个声明还不是要成为一个原型; 它可以是不指定参数types的旧式声明。

C11在这一领域没有发生重大变化。

因此,即使在2011年的ISO C标准中,旧式函数声明和定义(自1989年以来已经“过时”)仍然被允许在符合的代码中。

对于所有C版本,回到1989年,作为一个风格问题,没有什么理由不使用原型来实现所有function。 保留旧式的声明和定义只是为了避免破坏旧的代码。

是的,每个函数都必须有一个原型,但是原型可能会出现在单独的声明中或作为函数定义的一部分。 用C89编写的函数定义自然就有了原型,但是如果你用经典的K&R风格写东西,那么:

 main (argc, argv) int argc; char **argv; { ... } 

那么函数定义就没有原型了。 如果你写ANSI C(C89)风格,那么:

 main (int argc, char **argv) { ... } 

那么函数定义就有一个原型。

据我所知(在ANSI C89 / ISO C90),没有。 我不确定C99; 然而,我期望相同。

个人笔记:我只写函数原型时…

  1. 我需要(当A()调用B() B()时调用A())或
  2. 我正在导出函数; 否则,感觉是多余的。

编写新函数时的一个很好的提示是将它们与main的底部一起写下来,所以当你改变主意的时候,你不必修改原型。 不断修正原型,处理所有编译器的警告,当它们过时时,真的很乏味。

一旦你的function一起工作顺利,将代码移动到一个命名好的模块,并把原型放在一个同名的.h文件中。 这节省了很多时间。 我在5年中发现的最大的生产力援助。