为什么没有参数的函数(与实际函数定义相比)编译?
我刚刚遇到某人的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编译的例子:
在任何情况下,原型在本地的声明是没有用的,因为没有参数调用参考这个原型将是失败。 如果使用带有“非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默认会因编译器而异)。