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

Syd*_*ius 46 c c99 c89

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

Jon*_*ler 38

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

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

但是请注意,如果函数在没有原型的情况下接受了"正常促销"的参数(例如,一个charshort两个都被转换为int的函数;更严重的是,可能需要一个函数, a float而不是a 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();
Run Code Online (Sandbox Code Playgroud)

出现了.38

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

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

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

  • 幽默地使用“witter”(详细谈论一个琐碎的主题)的要点。我会减去“verbiage”(过多的冗长)的常见误用来表示“语言”,但在考虑了 C 标准的文本之后,我决定将其视为更微妙且非常针对性的幽默。 (3认同)

Kei*_*son 15

一个原型是一个函数声明指定类型的函数的参数.

前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版本,作为一种风格问题,没有理由不将原型用于所有功能.保留旧式声明和定义只是为了避免破坏旧代码.

  • @supercat:不正确.如果一个非变量函数的*definition*声明了2个参数,那么一个不能正确传递2个相应类型参数的调用就会有未定义的行为.使用非原型声明只会阻止编译器诊断错误. (2认同)
  • 如果你要提倡像这样非常不可移植的做法,至少要明确说明它们是不可移植的,并且你是根据一个已被取代多年的42年历史的文件做出假设的.倍.将错误数量的参数传递给函数是不可移植的,**并且不常见**. (2认同)

小智 13

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

  • 在C99,你是对的.在C89/C90中,您不需要预先声明一个函数; 它将被隐式声明为带有未定义参数列表的函数,并简单地通过用作函数返回int. (12认同)
  • C99和C99前标准之间的这种区别可能非常重要,这可以在comp.lang.c常见问题中得到证明:http://c-faq.com/malloc/mallocnocast.html (5认同)