我刚刚遇到了一些人的C代码,我很困惑为什么它要编译。有两点我不明白。
与实际函数定义相比,函数原型没有参数。 函数定义中的形参没有类型。
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
为什么会这样? 我已经在几个编译器中测试了它,它工作得很好。
我刚刚遇到了一些人的C代码,我很困惑为什么它要编译。有两点我不明白。
与实际函数定义相比,函数原型没有参数。 函数定义中的形参没有类型。
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
为什么会这样? 我已经在几个编译器中测试了它,它工作得很好。
当前回答
空参数列表表示“任何参数”,因此定义没有错。 缺失的类型被假定为int型。
我认为任何通过这一点的构建都缺乏配置的警告/错误级别,尽管如此,允许实际代码没有任何意义。
其他回答
在C语言中,func()意味着你可以传递任意数量的参数。如果你不想要参数,那么你必须声明为func(void)。传递给函数的类型,如果没有指定,默认为int。
在旧式的声明器中,
标识符列表必须不存在 声明器用于函数定义的头部 (Par.A.10.1)。参数类型信息不为 由声明提供。例如,声明
int f(), *fpi(), (*pfi)();
声明一个函数f返回一个整数,一个函数fpi返回一个整数指针,>和一个指针pfi返回一个整数函数。其中没有指定>的参数类型;它们是老式的。
在new-style声明中
Int strcpy(char *dest, const char *source), rand(void);
Strcpy是 函数返回int,有两个参数,第一个是字符 指针,第二个指针指向常量字符
来源:- K&R书
我希望这消除了你的疑虑。
正如@Krishnabhadra所说,其他用户之前的所有回答都有正确的解释,我只是想对一些观点做更详细的分析。
在Old-C中,就像在ANSI-C中一样,“无类型的形式参数”,取你的工作寄存器的尺寸或指令深度能力(阴影寄存器或指令累积周期),在一个8位MPU中,将是一个int16,在一个16位MPU中,将是一个int16,等等,在这种情况下,64位架构可以选择编译选项,如:-m32。
虽然它在高层的实现看起来更简单, 对于传递多个参数,程序员在控制维度数据类型步骤中的工作,变得更加苛刻。
在其他情况下,对于一些微处理器架构,ANSI编译器自定义,利用一些旧的特性来优化代码的使用,迫使这些“无类型的形式参数”的位置在工作寄存器内部或外部工作,今天你几乎可以使用“volatile”和“register”。
但值得注意的是,最现代的编译器, 不区分这两种类型的参数声明。
在linux下使用gcc编译的例子:
在任何情况下,原型的语句在本地是没有用的,因为没有参数的调用对这个原型的引用将是疏忽。 如果您使用带有“无类型形式参数”的系统进行外部调用,则继续生成声明性原型数据类型。
是这样的:
int myfunc(int param);
这就是为什么我通常建议人们使用以下方法编译代码:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
这些标志执行了一些事情:
-Wmissing-variable-declarations: It is impossible to declare a non-static function without getting a prototype first. This makes it more likely that a prototype in a header file matches with the actual definition. Alternatively, it enforces that you add the static keyword to functions that don't need to be visible publicly. -Wstrict-variable-declarations: The prototype must properly list the arguments. -Wold-style-definition: The function definition itself must also properly list the arguments.
在许多开源项目中也默认使用这些标志。例如,FreeBSD在Makefile中使用warnings =6构建时启用了这些标志。
int func ();是一个过时的函数声明,从没有C标准的日子,即K&R C的日子(1989年之前,第一个“ANSI C”标准发布)。
记住,在《K&R C》中还没有原型,关键字void也还没有被发明出来。你所能做的就是告诉编译器函数的返回类型。K&R C中的空参数列表表示“未指定但固定”的参数数量。Fixed意味着每次调用函数时必须使用相同数量的参数(而不是像printf这样的可变参数函数,每次调用时参数的数量和类型都可以变化)。
许多编译器会诊断这个构造;特别是gcc - wstrict - prototyping会告诉你“函数声明不是原型”,这是正确的,因为它看起来像一个原型(特别是如果你被c++毒害了!),但不是。这是一个老式的K&R C返回类型声明。
经验法则:永远不要让空参数列表声明为空,具体使用int func(void)。 这将K&R返回类型声明转换为适当的C89原型。编译器很高兴,开发人员很高兴,静态检查器也很高兴。不过,那些被c++的^W^Wfond误导的人可能会畏缩,因为当他们尝试练习外语技能时,他们需要输入额外的字符:-)