为什么没有参数的函数(与实际函数定义相比)编译?

我刚刚遇到某人的C代码,我很困惑,为什么它正在编译。 有两点我不明白。

首先,与实际的函数定义相比,函数原型没有参数。 其次,函数定义中的参数没有types。

#include <stdio.h> int func(); int func(param) { return param; } int main() { int bla = func(10); printf("%d", bla); } 

为什么这个工作? 我已经testing了几个编译器,它工作正常。

所有其他的答案是正确的,但只是为了完成

函数按以下方式声明:

  return-type function-name(parameter-list,...) { body... } 

return-type是函数返回的variablestypes。 这不能是数组types或函数types。 如果没有给出,那么int就是假定的

函数名称函数的名称

参数列表是函数用逗号分隔的参数列表。 如果没有给出任何参数,那么函数不会采取任何方式,应该使用一组空括号或关键字void来定义。 如果参数列表中没有variablestypes,则假定为int 。 数组和函数不会传递给函数,而是自动转换为指针。 如果列表以省略号(,…)终止,则没有设定的参数数目。 注意:当使用省略号时,头stdarg.h可以用来访问参数。

再次为了完整性。 从C11规范6:11:6 (第179页)

具有空括号的函数声明符 (不是原型格式参数types声明符)的使用是过时的function

在C的func()意味着你可以传递任意数量的参数。 如果你不需要参数,那么你必须声明为func(void) 。 如果未指定,则传递给函数的types默认为int

int func(); 是从没有C标准的日子即K&R C (1989年之前,第一个“ANSI C”标准出版的那一年)开始的过时函数声明。

请记住, K&R C没有原型,关键字void还没有发明。 你所能做的就是告诉编译器关于函数的返回types 。 K&R C中的空参数列表表示“未指定但固定”的参数数目。 固定意味着你必须每次调用具有相同数量的参数的函数(而不是象printf这样的可变参数函数,其中数字和types可以针对每个调用而改变)。

许多编译器会诊断这个结构; 特别是gcc -Wstrict-prototypes会告诉你“函数声明不是原型”,因为它看起来像一个原型(特别是如果你被C ++毒害!),但不是。 这是一种旧式K&R C返回types声明。

经验法则:永远不要将空的参数列表声明留​​空,使用int func(void)是特定的。 这将K&R返回types声明转换成适当的C89原型。 编译器很高兴,开发人员很高兴,静态跳棋很高兴。 但是,那些误导C ++的人可能会感到畏惧,因为他们在练习外语时需要input额外的字符:-)

  • 空参数列表的意思是“任何参数”,所以定义没有错。
  • 缺less的types被假定为int

我会考虑任何构build,通过这个缺乏configuration的警告/错误水平虽然,这是没有意义的这允许实际的代码。

这是K&R风格的函数声明和定义。 从C99标准(ISO / IEC 9899:TC3)

6.7.5.3节函数声明符(包括原型)

标识符列表仅声明该函数的参数的标识符。 函数声明器中的空列表是该函数定义的一部分,指定该函数没有参数。 函数声明器中的空列表不是该函数定义的一部分,它指定不提供有关参数数量或types的信息。 (如果两种functiontypes都是“旧式”,则不会比较参数types。)

6.11.6节函数声明符

具有空括号的函数声明符(不是原型格式参数types声明符)的使用是过时的function。

6.11.7节函数定义

具有单独的参数标识符和声明列表(不是原型格式参数types和标识符声明符)的函数定义的使用是过时的特征。

旧风格意味着K&R风格

例:

声明: int old_style();

定义:

 int old_style(a, b) int a; int b; { /* something to do */ } 

如果函数返回types和参数列表中没有给出types,则C假定为int 。 只有在这个怪异的事情之后才有可能。

函数定义如下所示。

 int func(int param) { /* body */} 

如果它是你写的原型

 int func(int param); 

在原型中,只能指定参数的types。 参数的名称不是必需的。 所以

 int func(int); 

此外,如果你不指定参数types,但名字int假定为types。

 int func(param); 

如果你走的更远,下面的作品。

 func(); 

当你编写func()时,编译器假定为int func() func() 。 但是不要把func()放在函数体中。 这将是一个函数调用

正如@Krishnabhadra所说,以前所有其他用户的回答都有一个正确的解释,我只是想对一些观点做更详细的分析。

在Old-C中,如ANSI-C中的“ 无typesforms参数 ”,在你的工作寄存器或指令深度能力(影子寄存器或指令累积周期)中,在一个8位MPU中,将是一个int16,在一个16位MPU等都将是一个int16等等,在64位体系结构可以select编译选项如:-m32。

虽然在高层看起来比较简单,但为了传递多个参数,程序员在控制数据types步骤中的工作变得更加苛刻。

在其他情况下,对于某些微处理器体系结构,ANSI编译器会自定义,利用这些旧function中的一些来优化代码的使用,迫使这些“无types的forms参数”在工作寄存器内外工作,与使用“易失性”和“注册”几乎一样。

但应该指出的是,最现代的编译器,并没有对这两类参数声明做出任何区分。

在linux下用gcc编译的例子:

main.c中

main2.c

main3.c
在任何情况下,原型在本地的声明是没有用的,因为没有参数调用参考这个原型将是失败。 如果使用带有“非types化forms参数”的系统,则对于外部调用,请继续生成声明性原型数据types。

喜欢这个:

 int myfunc(int param); 

关于参数types,这里已经有了正确的答案,但是如果你想从编译器中听到它,你可以尝试添加一些标志(无论如何,标志几乎总是一个好主意)。

使用gcc foo.c -Wextra编译你的程序gcc foo.c -Wextra我得到:

 foo.c: In function 'func': foo.c:5:5: warning: type of 'param' defaults to 'int' [-Wmissing-parameter-type] 

奇怪的是-Wextra没有抓住这个-Wextra (它不能识别-Wmissing-parameter-type由于某种原因,也许是上面提到的历史的那些)但是,

 foo.c:5:10: warning: parameter 'param' was not declared, defaulting to type 'int' [-pedantic] int func(param) ^ 1 warning generated. 

而对于原型问题,再次如上所述int func()指的是任意参数,除非你将其定义为int func(void) ,然后按照预期给出错误:

 foo.c: In function 'func': foo.c:6:1: error: number of arguments doesn't match prototype foo.c:3:5: error: prototype declaration foo.c: In function 'main': foo.c:12:5: error: too many arguments to function 'func' foo.c:5:5: note: declared here 

或在clang中:

 foo.c:5:5: error: conflicting types for 'func' int func(param) ^ foo.c:3:5: note: previous declaration is here int func(void); ^ foo.c:12:20: error: too many arguments to function call, expected 0, have 1 int bla = func(10); ~~~~ ^~ foo.c:3:1: note: 'func' declared here int func(void); ^ 2 errors generated. 

如果函数声明没有参数,即为空,那么它将采用未指定数目的参数。 如果你想让它不需要任何参数,那么把它改为:

 int func(void); 

这就是为什么我通常build议人们编译他们的代码:

 cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition 

这些标志强制执行一些事情:

  • -Wmissing-variable-declarations:不可能首先声明一个非静态的函数。 这使得头文件中的原型更有可能与实际的定义相匹配。 或者,它强制您将static关键字添加到不需要公开显示的函数中。
  • -Wstrict-variable-declarations:原型必须正确列出参数。
  • -Wold-style-definition:函数定义本身也必须正确列出参数。

这些标志在很多开源项目中也默认使用。 例如,在Makefile中用WARNS = 6编译时,FreeBSD会启用这些标志。

主席先生,在C ++( 和C ++ )中,您可以使用不同的参数定义多个具有相同名称的函数。 例如:

 int func(); int func(int test); int func(char testing123); 

应该编译。 要select使用哪个函数,只需在编译时将该variablestypes传递给括号即可。

例如:

 int testing123=2; func(testing123); 

将调用func(int test)。

 char test='a'; func(test); 

将调用func(char)。

你不需要函数头中的variables名,尽pipe只要函数原型(你知道,顶部只有一个函数没有代码的函数)匹配下面实际函数中的名字,你将会是A OKay(例如,而不是int func(int)你可以有int func(int avariable).

至于在没有types的情况下编译原型的variables,它可能是默认的types,可能是int(尽pipe我不确定哪种types默认会因编译器而异)。