我刚刚遇到某人的C代码,我很困惑为什么要编译 . 有两点我不明白 .
首先,与实际函数定义相比,函数原型没有参数 . 其次,函数定义中的参数没有类型 .
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
为什么这样做?我已经在几个编译器中对它进行了测试,它运行正常 .
10 回答
所有其他答案都是正确的,但仅适用于completion
再次为了完整起见 . From C11 specification 6:11:6(第179页)
在C
func()
中意味着您可以传递任意数量的参数 . 如果你不需要参数,那么你必须声明为func(void)
. 您传递给函数的类型,如果未指定,则默认为int
.int func();
是一个过时的函数声明,从没有C标准的日子开始,即 K&R C 的日子(1989年之前,即第一个"ANSI C"标准发布的那一年) .请记住,K&R C中没有原型,关键字
void
尚未发明 . 您所能做的就是告诉编译器函数的返回类型 . K&R C中的空参数列表表示"an unspecified but fixed"个参数 . Fixed表示每次必须使用相同数量的args调用该函数(与printf
之类的可变函数相反,其中数字和类型可能因每次调用而异) .许多编译器会诊断出这个结构;特别是
gcc -Wstrict-prototypes
会告诉你"function declaration isn't a prototype",这是现货,因为它看起来像一个原型(特别是如果你被C毒药!),但isn 't. It'是旧式K&R C返回类型声明 .Rule of thumb: 永远不要将空参数列表声明留空,请使用
int func(void)
具体 . 这将K&R返回类型声明转换为适当的C89原型 . 编译器很高兴,开发人员很高兴,静态跳棋很开心 . 那些被C语言误导的人可能会感到畏缩,因为他们在尝试锻炼外语时需要输入额外的字符:-)空参数列表表示"any arguments",因此定义没有错误 .
缺少的类型假定为
int
.我认为任何传递此功能的构建都缺少配置的警告/错误级别,但这样做是没有必要允许实际的代码 .
这是 K&R 样式函数声明和定义 . 来自C99标准(ISO / IEC 9899:TC3)
第6.7.5.3节函数声明符(包括原型)
第6.11.6节函数声明符
第6.11.7节函数定义
哪种旧式意味着 K&R 风格
例:
声明:
int old_style();
定义:
C assumes int if no type is given on function return type and parameter list . 只有这个规则才能实现奇怪的事情 .
函数定义如下所示 .
如果它是你写的原型
在原型中,您只能指定参数的类型 . 参数名称不是必需的 . 所以
此外,如果您不指定参数类型,但名称
int
被假定为类型 .如果你走得更远,跟随也有效 .
当您编写
func()
时,编译器会假定int func()
. 但是不要将func()
放在函数体内 . 这将是一个函数调用正如@Krishnabhadra所述,之前所有其他用户的回复都有正确的解释,我只想对某些要点进行更详细的分析 .
在旧的-C和ANSI-C中的“ untyped formal parameter ”中,取一个工作寄存器的尺寸或指令深度能力(影子寄存器或指令累积周期),在8位MPU中,将是一个int16,在16位MPU中所以将是一个int16,在这种情况下,64位架构可能会选择编译选项,如:-m32 .
尽管在高级别上实现似乎更简单,但是为了传递多个参数,程序员在控制维数数据类型步骤中的工作变得更加苛刻 .
在其他情况下,对于某些微处理器体系结构,ANSI编译器定制,利用这些旧功能中的一些来优化代码的使用,迫使这些“无类型正式参数”的位置在工作寄存器内部或外部工作,今天你得到使用“volatile”和“register”几乎相同 .
But it should be noted that the most modern compilers, not make any distinction between the two types of parameters declaration.
在linux下用gcc编译的例子:
在任何情况下,本地原型的声明都是没有用的,因为没有参数的调用没有参考这个原型会被忽略 . 如果将系统与"untyped formal parameter"一起使用,则对于外部调用,请继续生成声明性原型数据类型 .
像这样:
关于参数类型,这里已经有正确的答案,但是如果你想从编译器中听到它,你可以尝试添加一些标志(标志几乎总是一个好主意) .
使用_771409编译你的程序我得到:
奇怪的是
-Wextra
没有 grab 这个clang
(由于某些原因,它不承认-Wmissing-parameter-type
,也许是上面提到的历史问题),但是-pedantic
:对于上面再次提到的原型问题,
int func()
指的是任意参数,除非您将其明确地定义为int func(void)
,然后会按预期给出错误:或者在
clang
中:如果函数声明没有参数,即空,那么它将采用未指定数量的参数 . 如果你想让它不带参数,那么将它改为:
这就是为什么我通常建议人们用以下代码编译代码:
这些标志强制执行以下几项操作:
-Wmissing-variable-declarations:如果不先获取原型,就不可能声明非静态函数 . 这使得头文件中的原型更有可能与实际定义匹配 . 或者,它强制您将static关键字添加到不需要公开显示的函数中 .
-Wstrict-variable-declarations:原型必须正确列出参数 .
-Wold-style-definition:函数定义本身也必须正确列出参数 .
默认情况下,许多开源项目中也使用这些标志 . 例如,在Makefile中使用WARNS = 6构建时,FreeBSD启用了这些标志 .