我刚刚遇到了一些人的C代码,我很困惑为什么它要编译。有两点我不明白。

与实际函数定义相比,函数原型没有参数。 函数定义中的形参没有类型。


#include <stdio.h>

int func();

int func(param)
{
    return param;
}

int main()
{
    int bla = func(10);    
    printf("%d", bla);
}

为什么会这样? 我已经在几个编译器中测试了它,它工作得很好。


当前回答

这就是为什么我通常建议人们使用以下方法编译代码:

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(void);

在旧式的声明器中,

标识符列表必须不存在 声明器用于函数定义的头部 (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书

我希望这消除了你的疑虑。

如果函数返回类型和形参列表上没有给出类型,则C语言假定为int。只有遵循这条规则,才有可能发生奇怪的事情。

函数定义是这样的。

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

如果它是一个原型,你写

int func(int param);

在原型中,你只能指定参数的类型。参数名称为非必选项。所以

int func(int);

同样,如果你没有指定参数类型,但名称int被假设为类型。

int func(param);

如果你走得更远,跟着也行。

func();

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

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

A function is declared in the following manner: return-type function-name(parameter-list,...) { body... } return-type is the variable type that the function returns. This can not be an array type or a function type. If not given, then int is assumed. function-name is the name of the function. parameter-list is the list of parameters that the function takes separated by commas. If no parameters are given, then the function does not take any and should be defined with an empty set of parenthesis or with the keyword void. If no variable type is in front of a variable in the paramater list, then int is assumed. Arrays and functions are not passed to functions, but are automatically converted to pointers. If the list is terminated with an ellipsis (,...), then there is no set number of parameters. Note: the header stdarg.h can be used to access arguments when using an ellipsis.

为了完整起见。来自C11规范6:11:6(第179页)

使用带有空括号的函数声明器(不是 原型格式参数类型声明器)是过时的 特性。

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误导的人可能会畏缩,因为当他们尝试练习外语技能时,他们需要输入额外的字符:-)