简体   繁体   English

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

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

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

It depends on what you mean by 'truly standards compliant'. 这取决于“真正符合标准”的含义。 However, the short answer is "it is a good idea to ensure that all functions have a prototype in scope before being used". 然而,简短的回答是“在使用之前确保所有功能都具有范围原型是一个好主意”。

A more qualified answer notes that if the function accepts variable arguments (notably the printf() family of functions), then a prototype must be in scope to be strictly standards compliant. 更合格的答案指出,如果函数接受变量参数(特别是printf()函数族),那么原型必须在范围内严格遵守标准。 This is true of C89 (from ANSI) and C90 (from ISO; the same as C89 except for the section numbering). C89(来自ANSI)和C90(来自ISO;与C89相同,除了章节编号)也是如此。 Other than 'varargs' functions, though, functions which return an int do not have to be declared, and functions that return something other than an int do need a declaration that shows the return type but do not need the prototype for the argument list. 但是,除了'varargs'函数之外,不必声明返回int函数,并且返回除int之外的函数的函数确实需要一个声明来显示返回类型,但不需要参数列表的原型。

Note, however, that if the function takes arguments that are subject to 'normal promotions' in the absence of prototypes (for example, a function that takes a char or short - both of which are converted to int ; more seriously, perhaps, a function that takes a float instead of a double ), then a prototype is needed. 但请注意,如果函数在没有原型的情况下接受了“正常促销”的参数(例如,一个接受charshort的函数 - 两者都转换为int ;更严重的是,也许,采用float而不是double函数,然后需要原型。 The standard was lax about this to allow old C code to compile under standard conformant compilers; 标准是松散的,允许旧的C代码在标准符合的编译器下编译; older code was not written to worry about ensuring that functions were declared before use - and by definition, older code did not use prototypes since they did not become available in C until there was a standard. 旧代码并不是为了确保函数在使用前被声明而被编写 - 根据定义,旧代码不使用原型,因为在有标准之前它们没有在C中可用。

C99 disallows 'implicit int'...that means both oddball cases like ' static a; C99不允许'隐含的int'......这意味着两个奇怪的情况,比如' static a; ' (an int by default) and also implicit function declarations. '(默认为int )以及隐式函数声明。 These are mentioned (along with about 50 other major changes) in the foreword to ISO/IEC 9899:1999, which compares that standard to the previous versions: 在ISO / IEC 9899:1999的前言中提到了这些(以及大约50个其他主要变化),该标准将该标准与先前版本进行了比较:

  • remove implicit int 删除隐式int
    ...
  • remove implicit function declaration 删除隐式函数声明

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

If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration: 如果函数调用中带括号的参数列表之前的表达式仅包含一个标识符,并且如果此标识符没有可见的声明,则标识符将在包含函数调用的最内层块中隐式声明,就像声明一样:

 extern int identifier(); 

appeared. 出现了。 38 38

38 That is, an identifier with block scope declared to have external linkage with type function without parameter information and returning an int . 38也就是说,一个带有块作用域的标识符被声明为与没有参数信息的类型函数有外部链接并返回一个int If in fact it is not defined as having type “function returning int ,” the behavior is undefined. 如果实际上它没有定义为具有“函数返回int ”类型,则行为是未定义的。

This paragraph is missing in the 1999 standard. 1999年的标准中缺少这一段。 I've not (yet) tracked the change in verbiage that allows static a; 我还没有(还)跟踪允许static a;变化的措辞的变化static a; in C90 and disallows it (requiring static int a; ) in C99. 在C90中,在C99中不允许它(需要static int a; )。

Note that if a function is static, it may be defined before it is used, and need not be preceded by a declaration. 请注意,如果函数是静态的,则可以在使用它之前定义它,并且不需要在声明之前。 GCC can be persuaded to witter if a non-static function is defined without a declaration preceding it ( -Wmissing-prototypes ). 如果定义了非静态函数而没有在其前面的声明( -Wmissing-prototypes ),则可以说服GCC。

A prototype is a function declaration that specifies the types of the function's parameters. 原型是一个函数声明,它指定函数参数的类型。

Pre-ANSI C (the language described by the 1978 first edition of Kernighan & Ritchie's "The C Programming Language") did not have prototypes; 前ANSI C(1978年第一版Kernighan&Ritchie所描述的语言“The C Programming Language”)没有原型; it was not possible for a function declaration to describe the number or types of the parameters. 函数声明不可能描述参数的数量或类型。 It was up to the caller to pass the correct number and type of arguments. 由调用者传递正确的参数数量和类型。

ANSI C introduced "prototypes", declarations that specify the types of the parameters (a feature borrowed from early C++). ANSI C引入了“原型”,这些声明指定了参数的类型(从早期的C ++中借用的一个特性)。

As of C89/C90 (the ANSI and ISO standards describe the same language), it's legal to call a function with no visible declaration; 从C89 / C90(ANSI和ISO标准描述相同的语言)开始,调用没有可见声明的函数是合法的; an implicit declaration is provided. 提供了隐式声明。 If the implicit declaration is incompatible with the actual definition (say, calling sqrt("foo") , then the behavior is undefined. Neither this implicit declaration nor a non-prototype declaration can be compatible with a variadic function, so any call to a variadic function (like printf or scanf ) must have a visible prototype. 如果隐式声明与实际定义不兼容(比如调用sqrt("foo") ,那么行为是未定义的。这个隐式声明和非原型声明都不能与可变参数函数兼容,所以任何调用都是可变函数(如printfscanf )必须具有可见原型。

C99 dropped implicit declarations. C99删除了隐式声明。 Any call to a function without a visible declaration is a constraint violation, requiring a compiler diagnostic. 对没有可见声明的函数的任何调用都是违反约束的,需要编译器诊断。 But that declaration is still not required to be a prototype; 但该声明仍然不需要成为原型; it can be an old-style declaration that doesn't specify parameter types. 它可以是不指定参数类型的旧式声明。

C11 made no significant changes in this area. C11在这方面没有发生重大变化。

So even as of the 2011 ISO C standard, old-style function declarations and definitions (which have been "obsolescent" since 1989) are still permitted in conforming code. 因此,即使在2011 ISO C标准中,仍然允许使用旧式函数声明和定义(自1989年以来“过时”)。

For all versions of C going back to 1989, as a matter of style, there is very little reason not to use prototypes for all functions. 对于可以追溯到1989年的所有C版本,作为一种风格问题,没有理由不将原型用于所有功能。 Old-style declarations and definitions are kept only to avoid breaking old code. 保留旧式声明和定义只是为了避免破坏旧代码。

No, functions do not always need a prototype. 不,功能并不总是需要原型。 The only requirement is that a function be "declared" before you use it. 唯一的要求是在使用函数之前“声明”它。 There are two ways to declare a function: to write a prototype, or to write the function itself (called a "definition.") A definition is always a declaration, but not all declarations are definitions. 声明函数有两种方法:编写原型,或编写函数本身(称为“定义”。)定义始终是声明,但并非所有声明都是定义。

A nice tip when writing new functions is to write them upside-down with main at the bottom so when you change your mind about the function's args or return type you don't have to fix the prototype too. 编写新函数时,一个很好的提示是将它们颠倒写入,底部是main,所以当你改变主意关于函数的args或返回类型时,你也不必修复原型。 Constantly fixing prototypes, and dealing with all the compiler's warnings when they are out of date gets really tedious. 不断修复原型,并在它们过时时处理所有编译器的警告变得非常乏味。

Once you have your functions working smoothly together move the code to a well-named module and put the prototypes in a .h file of the same name. 一旦您的功能顺利运行,将代码移动到一个命名良好的模块,并将原型放在同名的.h文件中。 It saves serious time. 它节省了大量时间。 The biggest productivity aid I've found in 5 years. 我在5年内发现的最大生产力援助。

Yes, every function must have a prototype, but that prototype may appear either in a separate declaration or as part of the function's definition. 是的,每个函数都必须有一个原型,但该原型可能出现在单独的声明中,也可能出现在函数定义的一部分中。 Function definitions written in C89 and up naturally have prototypes, but if you write things in classic K&R style, thus: 用C89编写的函数定义自然会有原型,但是如果你用经典的K&R风格写东西,那么:

main (argc, argv)

  int argc;
  char **argv;

{
  ...
}

then the function definition has no prototype. 然后函数定义没有原型。 If you write ANSI C (C89) style, thus: 如果你编写ANSI C(C89)样式,那么:

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

then the function definition has a prototype. 然后函数定义有一个原型。

To the best of my knowledge (in ANSI C89/ISO C90), no. 据我所知(在ANSI C89 / ISO C90中),没有。 I am unsure about C99; 我不确定C99; however, I would expect the same. 但是,我希望也一样。

Personal Note: I only write function prototypes when... 个人提示:我只在编写函数原型时...

  1. I need to (when A() calls B() and B() calls A()), or 我需要(当A()调用B() B()调用A()),或
  2. I am exporting the function; 我正在导出这个功能; otherwise, it feels superfluous. 否则,感觉多余。

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

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