繁体   English   中英

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

[英]Are prototypes required for all functions in C89, C90 or C99?

为了真正符合标准,C中的所有函数(main除外)都必须有原型,即使它们只是在同一个翻译单元中定义之后才使用它们吗?

这取决于“真正符合标准”的含义。 然而,简短的回答是“在使用之前确保所有功能都具有范围原型是一个好主意”。

更合格的答案指出,如果函数接受变量参数(特别是printf()函数族),那么原型必须在范围内严格遵守标准。 C89(来自ANSI)和C90(来自ISO;与C89相同,除了章节编号)也是如此。 但是,除了'varargs'函数之外,不必声明返回int函数,并且返回除int之外的函数的函数确实需要一个声明来显示返回类型,但不需要参数列表的原型。

但请注意,如果函数在没有原型的情况下接受了“正常促销”的参数(例如,一个接受charshort的函数 - 两者都转换为int ;更严重的是,也许,采用float而不是double函数,然后需要原型。 标准是松散的,允许旧的C代码在标准符合的编译器下编译; 旧代码并不是为了确保函数在使用前被声明而被编写 - 根据定义,旧代码不使用原型,因为在有标准之前它们没有在C中可用。

C99不允许'隐含的int'......这意味着两个奇怪的情况,比如' static a; '(默认为int )以及隐式函数声明。 在ISO / IEC 9899:1999的前言中提到了这些(以及大约50个其他主要变化),该标准将该标准与先前版本进行了比较:

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

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

如果函数调用中带括号的参数列表之前的表达式仅包含一个标识符,并且如果此标识符没有可见的声明,则标识符将在包含函数调用的最内层块中隐式声明,就像声明一样:

 extern int identifier(); 

出现了。 38

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

1999年的标准中缺少这一段。 我还没有(还)跟踪允许static a;变化的措辞的变化static a; 在C90中,在C99中不允许它(需要static int a; )。

请注意,如果函数是静态的,则可以在使用它之前定义它,并且不需要在声明之前。 如果定义了非静态函数而没有在其前面的声明( -Wmissing-prototypes ),则可以说服GCC。

原型是一个函数声明,它指定函数参数的类型。

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

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

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

C99删除了隐式声明。 对没有可见声明的函数的任何调用都是违反约束的,需要编译器诊断。 但该声明仍然不需要成为原型; 它可以是不指定参数类型的旧式声明。

C11在这方面没有发生重大变化。

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

对于可以追溯到1989年的所有C版本,作为一种风格问题,没有理由不将原型用于所有功能。 保留旧式声明和定义只是为了避免破坏旧代码。

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

编写新函数时,一个很好的提示是将它们颠倒写入,底部是main,所以当你改变主意关于函数的args或返回类型时,你也不必修复原型。 不断修复原型,并在它们过时时处理所有编译器的警告变得非常乏味。

一旦您的功能顺利运行,将代码移动到一个命名良好的模块,并将原型放在同名的.h文件中。 它节省了大量时间。 我在5年内发现的最大生产力援助。

是的,每个函数都必须有一个原型,但该原型可能出现在单独的声明中,也可能出现在函数定义的一部分中。 用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. 我正在导出这个功能; 否则,感觉多余。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM