我刚遇到某人的C代码,我很困惑为什么要编译。有两点我不明白。
首先,函数原型与实际函数定义相比没有参数。其次,函数定义中的参数没有类型。
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
为什么这样做?我已经在几个编译器中对它进行了测试,它运行正常。
答案 0 :(得分:268)
所有其他答案都是正确的,但仅适用于completion
以下列方式声明函数:
return-type function-name(parameter-list,...) { body... }
return-type 是函数返回的变量类型。这不能是数组类型或函数类型。 如果没有给出,那么int 假定。
function-name 是函数的名称。
parameter-list 是函数以逗号分隔的参数列表。 如果没有给出参数,那么函数 不带任何,应该用空集定义 括号或关键字void。如果前面没有变量类型 参数列表中的变量,则假定为 。数组和 函数不会传递给函数,但会自动转换 指针。如果列表以省略号(,...)结束,那么 没有设定数量的参数。注意:标题stdarg.h可以 用于在使用省略号时访问参数。
再次为了完整起见。 From C11 specification 6:11:6(第179页)
使用带空括号的函数声明符(不是 prototype-format参数类型声明符)是一个过时的 特征
答案 1 :(得分:158)
在C func()
中意味着您可以传递任意数量的参数。如果您不需要参数,则必须声明为func(void)
。您传递给函数的类型,如果未指定,则默认为int
。
答案 2 :(得分:57)
int func();
是一个过时的函数声明,从没有C标准的日子开始,即 K&amp; RC 的日子(1989年之前,第一个“ANSI C”标准的年份)已发表)。
请记住,K&amp; R C 中没有没有原型,关键字void
尚未发明。您所能做的就是告诉编译器函数的返回类型。 K&amp; R C中的空参数列表表示“未指定但固定”的参数数量。修复意味着您必须每次使用相同个参数来调用该函数(而不是像printf
这样的可变参数函数,其中数字和类型可以每次通话都有所不同。)
许多编译器会诊断出这个结构;特别是gcc -Wstrict-prototypes
将告诉你“函数声明不是原型”,这是现场的,因为它看起来像原型(特别是如果你被C ++中毒了!),但是不是。这是旧式的K&amp; R C返回类型声明。
经验法则:永远不要将空参数列表声明留空,请使用int func(void)
具体。
这将K&amp; R返回类型声明转换为适当的C89原型。编译器很高兴,开发人员很高兴,静态的跳棋很开心。那些被C ++误导的人可能会感到畏缩,因为他们在尝试锻炼外语时需要输入额外的字符: - )
答案 3 :(得分:53)
int
。我会认为任何传递此内容的构建都缺少配置的警告/错误级别,但这样做是没有必要允许实际的代码。
答案 4 :(得分:29)
K&amp; R 样式函数声明和定义。来自C99标准(ISO / IEC 9899:TC3)
第6.7.5.3节函数声明符(包括原型)
标识符列表仅声明函数参数的标识符。一个空的 函数声明符中的列表是该函数定义的一部分,用于指定 功能没有参数。 函数声明符中不属于a的空列表 该函数的定义指定没有关于数量或类型的信息 提供参数。 (如果两种函数类型都是“旧样式”,则不会比较参数类型。)
第6.11.6节函数声明符
使用带有空括号的函数声明符(不是prototype-format参数 类型声明者)是过时的功能。
第6.11.7节功能定义
使用具有单独参数标识符和声明列表的函数定义 (不是prototype-format参数类型和标识符声明符)是一个过时的功能。
旧样式的意思是 K&amp; R 样式
示例:
声明:int old_style();
定义:
int old_style(a, b)
int a;
int b;
{
/* something to do */
}
答案 5 :(得分:15)
C假定为int
。只有这个规则才能实现奇怪的事情。
函数定义如下所示。
int func(int param) { /* body */}
如果它是你写的原型
int func(int param);
在原型中,您只能指定参数的类型。参数名称不是必需的。所以
int func(int);
此外,如果您不指定参数类型,但假定名称int
为类型。
int func(param);
如果你走得更远,下面的工作也是如此。
func();
编写int func()
时,编译器会假定func()
。但是不要将func()
放在函数体中。这将是一个函数调用
答案 6 :(得分:11)
正如@Krishnabhadra所述,之前所有其他用户的回复都有正确的解释,我只是想对某些要点进行更详细的分析。
在旧C中,如ANSI-C中的“无类型形式参数”,取8bit的工作寄存器或指令深度能力(影子寄存器或指令累积周期)的尺寸MPU,将是一个16位MPU中的int16,因此将是一个int16,在这种情况下,64位架构可以选择编译选项,如:-m32。
虽然在高级别上看起来似乎更简单, 对于传递多个参数,程序员在控制维数数据类型步骤中的工作变得更加苛刻。
在其他情况下,对于某些微处理器体系结构,ANSI编译器定制,利用这些旧功能中的一些来优化代码的使用,迫使这些“无类型的形式参数”的位置在工作寄存器内部或外部工作,今天你使用“volatile”和“register”几乎一样。
但应该注意到最现代的编译器, 不要对两种类型的参数声明做任何区分。
在linux下使用gcc进行编译的示例:
在任何情况下,本地原型的声明都是没有用的,因为没有参数的调用没有参考这个原型会被忽略。
如果您使用带有“无类型形式参数”的系统,则对于外部调用,请继续生成声明性原型数据类型。
像这样:
int myfunc(int param);
答案 7 :(得分:5)
关于参数类型,这里已经有了正确的答案,但如果你想从编译器中听到它,你可以尝试添加一些标志(标志几乎总是一个好主意)。
使用gcc foo.c -Wextra
编译您的程序我得到:
foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
奇怪的是-Wextra
没有抓住clang
的内容(由于某些原因,它无法识别-Wmissing-parameter-type
,可能是上面提到的历史记录),但是-pedantic
:
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.
答案 8 :(得分:3)
如果函数声明没有参数,即为空,那么它将采用未指定数量的参数。如果你想让它不带参数,那么把它改成:
int func(void);
答案 9 :(得分:0)
这就是为什么我通常建议人们用以下代码编译代码:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
这些标志强制执行以下几项操作:
这些标志在许多开源项目中也默认使用。例如,在Makefile中使用WARNS = 6构建时,FreeBSD启用了这些标志。
答案 10 :(得分:0)
在旧式声明符中,
<块引用>标识符列表必须不存在,除非 声明符用于函数定义的头部 (第 A.10.1 段)。没有关于参数类型的信息 由声明提供。例如声明
int f(), *fpi(), (*pfi)();
<块引用>
声明一个返回整数的函数 f,一个返回一个整数指针的函数 fpi,以及一个返回一个整数的函数的指针 pfi。在这些中都没有>指定的参数类型;它们是旧式的。
<块引用>在新式声明中
int strcpy(char *dest, const char *source), rand(void);
strcpy 是一个 函数返回 int,有两个参数,第一个是字符 指针,第二个是指向常量字符的指针
来源:- K&R 书籍
希望能消除你的疑惑..