为了真正符合标准,C语言中的所有函数(除了main函数)是否都必须有原型,即使它们只在同一翻译单元中定义后使用?
printf()
系列函数),则必须有原型在作用域内才能严格符合标准。这适用于C89(来自ANSI)和C90(来自ISO;除了章节编号,与C89相同)。但除了'varargs'函数之外,返回int
的函数不必声明,返回其他类型的函数需要显示返回类型的声明,但不需要参数列表的原型。char
或short
的函数 - 这两个都转换为int
;或者接受float
而不是double
的函数),则需要原型。标准对此比较宽松,以允许旧C代码在符合标准的编译器下编译;旧代码不需要担心在使用之前声明函数 - 定义上,旧代码不使用原型,因为在有标准之前,原型不可用于C。static a;
”(默认为int
)和隐式函数声明。这些被提到(连同其他大约50个主要更改)在ISO/IEC 9899:1999的前言中,该标准将其与以前的版本进行了比较:int
如果函数调用中括号中的参数列表之前的表达式仅由标识符组成,并且对于此标识符没有可见的声明,则该标识符会被隐式声明,就好像在包含函数调用的最内层块中声明了:
extern int identifier();
出现了38。
38这意味着一个具有外部链接的块作用域标识符,其类型为没有参数信息且返回
int
的函数。如果实际上它未被定义为具有“返回int
的函数”类型,则行为是未定义的。这段话在1999年标准中缺失。我还没有追踪到措辞上的变化,使得C90允许使用
static a;
而C99则不允许(需要static int a;
)。请注意,如果函数是静态的,可以在使用之前定义,并且不必在前面加上声明。GCC可以通过指定选项
-Wmissing-prototypes
来发出警告,如果没有在使用之前声明非静态函数。
<stdarg.h>
和显式可变参数函数被引入的原因之一。你所提到的一个例子是 POSIX 的 open()
函数,它传统上需要 2 或 3 个参数; POSIX 将其指定为可变参数函数。问题是关于 C89/C90 和 C99,而不是 ANSI 之前的 C。 - Keith Thompsonprintf()
调用由于缺少原型而失败吗?换句话说,“必须有可见的原型”是什么意思?(int main(void){int i = 1; printf("%d", i); }
) - jfsint
函数,并且其参数与调用中传递的参数完全匹配,考虑到标准类型提升。这样的编译器通常会在同一编译单元中找到与推断不一致的声明时报错。如果没有找到声明,并且参数类型与分开编译的函数定义没有正确猜测(进行比较),问题可能会在链接时被检测出来,也可能不会。 - supercatfoo
,则行为是未定义的。例如,如果foo
被定义为具有2个int
参数,则使用3个foo
参数调用它会产生未定义的行为。无论您尝试使用这种非可移植性的黑客技巧做什么,都有更好且更可移植的方法来实现它。 - Keith Thompsonmain (argc, argv)
int argc;
char **argv;
{
...
}
那么函数定义就没有原型。如果您使用 ANSI C(C89)风格编写,如下所示:
main (int argc, char **argv) { ... }
那么函数定义就有原型。
void func(int n) { /* ... */ }
包括一个原型。 - Keith Thompson