为什么没有参数的函数(与实际函数定义相比)编译?

Adm*_*onB 385 c parameters function-parameter function-prototypes

我刚刚遇到某人的C代码,我很困惑为什么要编译.有两点我不明白.

首先,与实际函数定义相比,函数原型没有参数.其次,函数定义中的参数没有类型.

#include <stdio.h>

int func();

int func(param)
{
    return param;
}

int main()
{
    int bla = func(10);    
    printf("%d", bla);
}
Run Code Online (Sandbox Code Playgroud)

为什么这样做?我已经在几个编译器中测试过,它运行正常.

Kri*_*dra 270

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

函数以下列方式声明:

  return-type function-name(parameter-list,...) { body... }
Run Code Online (Sandbox Code Playgroud)

return-type是函数返回的变量类型.这不能是数组类型或函数类型.如果没有给出,则假定为int.

function-name函数的名称.

parameter-list是函数用逗号分隔的参数列表.如果没有给出参数,则该函数不带任何参数,并且应该用空的括号或用关键字void定义.如果参数列表中的变量前面没有变量类型,则假定为int.数组和函数不会传递给函数,但会自动转换为指针.如果列表以省略号(,...)结束,则没有设定数量的参数.注意:标头stdarg.h可用于在使用省略号时访问参数.

再次为了完整起见.从C11规范6:11:6(第179页)

使用功能与空括号声明符(未原型格式参数类型说明符)是一个过时特征.

  • ***“如果参数列表中的变量前面没有变量类型,则假定为 int。”*** 我在您提供的链接中看到了这一点,但我在任何标准 c89、c99 中都找不到它。 . 你能提供另一个来源吗? (2认同)

Ton*_*ion 158

在C中func()意味着您可以传递任意数量的参数.如果你不需要参数,那么你必须声明为func(void).您传递给函数的类型,如果未指定,则默认为int.

  • 我宁愿说隐含的int**在过去的日子里很常见.它当然不再存在,在C99中它被从C中移除. (4认同)
  • 实际上没有单一的类型默认为int.实际上,所有args都默认为int(甚至是返回类型).调用`func(42,0x42);`(其中*all*调用必须使用两个args形式)是完全可以的. (3认同)
  • 值得注意的是,这个答案适用于具有空参数列表的函数原型,但*不是*具有空参数列表的函数定义. (2认同)

Jen*_*ens 57

int func();从没有C标准的日子开始,这是一个过时的功能声明,即K&R C的日子(1989年之前,第一个"ANSI C"标准发布的那一年).

请记住,K&R C没有原型,关键字void尚未发明.您所能做的就是告诉编译器函数的返回类型.K&R C中的空参数列表表示"未指定但固定"的参数数量.固定意味着您必须每次都使用相同数量的args 调用该函数(与可变参数函数相反,例如printf,每次调用的数字和类型可能不同).

许多编译器会诊断出这个结构; 特别gcc -Wstrict-prototypes会告诉你"函数声明不是原型",这是一个现场,因为它看起来像一个原型(特别是如果你被C++中毒!),但事实并非如此.这是一种旧式的K&R C返回型声明.

经验法则:永远不要将空参数列表声明留​​空,用于int func(void)具体.这将K&R返回类型声明转换为适当的C89原型.编译器很高兴,开发人员很高兴,静态的跳棋很开心.那些被C++误导的人可能会感到畏缩,因为他们在尝试锻炼外语时需要输入额外的字符:-)

  • 请不要将其与 C++ 联系起来。空参数列表意味着“没有参数”,这是“常识”,世界上的人们没有兴趣处理 K&amp;R 人在大约 40 年前犯下的错误。但委员会专家们不断将反自然的选择拖入 C99、C11。 (3认同)

unw*_*ind 53

  • 空参数列表表示"任何参数",因此定义没有错.
  • 假设缺少类型int.

我认为任何通过它的构建都缺少配置的警告/错误级别,但是这样做是没有必要允许实际的代码.


Lei*_*Mou 30

它是K&R风格的功能声明和定义.来自C99标准(ISO/IEC 9899:TC3)

第6.7.5.3节函数声明符(包括原型)

标识符列表仅声明函数参数的标识符.函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数.函数声明符中的空列表不是该函数定义的一部分,它指定不提供有关参数数量或类型的信息.(如果两种函数类型都是"旧样式",则不会比较参数类型.)

第6.11.6节函数声明符

使用带有空括号的函数声明符(不是prototype-format参数类型声明符)是一个过时的功能.

第6.11.7节函数定义

使用具有单独的参数标识符和声明列表(而不是原型格式参数类型和标识符声明符)的函数定义是一个过时的功能.

哪种旧式意味着K&R风格

例:

宣言: int old_style();

定义:

int old_style(a, b)
    int a; 
    int b;
{
     /* something to do */
}
Run Code Online (Sandbox Code Playgroud)


Shi*_*dim 15

int如果函数返回类型和参数列表中没有给出类型,则C假定.只有这个规则才能实现奇怪的事情.

函数定义如下所示.

int func(int param) { /* body */}
Run Code Online (Sandbox Code Playgroud)

如果它是你写的原型

int func(int param);
Run Code Online (Sandbox Code Playgroud)

在原型中,您只能指定参数的类型.参数名称不是必需的.所以

int func(int);
Run Code Online (Sandbox Code Playgroud)

此外,如果您不指定参数类型,但将名称int假定为类型.

int func(param);
Run Code Online (Sandbox Code Playgroud)

如果你走得更远,下面的工作也是如此.

func();
Run Code Online (Sandbox Code Playgroud)

编译器假定int func()你写的时候func().但是不要放入func()功能体内.这将是一个函数调用

  • 空参数列表与隐式 int 类型无关。`int func()` 不是 `int func(int)` 的隐式形式。 (4认同)

RTO*_*kit 11

正如@Krishnabhadra所述,之前所有其他用户的回复都有正确的解释,我只想对某些要点进行更详细的分析.

在旧C中,如ANSI-C中的" 无类型形式参数 ",取8位MPU中的工作寄存器或指令深度能力(影子寄存器或指令累积周期)的尺寸,将是16位,16位MPU等将是一个int16,在这种情况下,64位架构可能会选择编译选项,如:-m32.

虽然在高级别上看起来似乎更简单,但是为了传递多个参数,程序员在控制维数数据类型步骤中的工作变得更加苛刻.

在其他情况下,对于某些微处理器体系结构,ANSI编译器定制,利用这些旧功能中的一些来优化代码的使用,迫使这些"无类型的形式参数"的位置在工作寄存器内部或外部工作,今天你得到使用"volatile"和"register"几乎相同.

但应该指出的是,最现代的编译器,没有对两种类型的参数声明做任何区分.

在linux下使用gcc进行编译的示例:

main.c中

main2.c

main3.c  
在任何情况下,本地原型的声明都是没有用的,因为没有参数的调用没有参考这个原型会被忽略.如果将系统与"无类型形式参数"一起使用,则对于外部调用,请继续生成声明性原型数据类型.

像这样:

int myfunc(int param);
Run Code Online (Sandbox Code Playgroud)

  • 我已经麻烦地优化图像,因为图像的字节大小是最小的.我认为图片可以快速查看生成的代码中缺少差异.我一直在测试代码,生成它声称的真实文档,而不仅仅是对问题进行理论化.但并非所有人都以同样的方式看世界.我非常抱歉,我试图向社区提供更多信息,以至于一直困扰着你. (5认同)

non*_*one 5

关于参数类型,这里已经有正确的答案,但如果你想从编译器中听到它,你可以尝试添加一些标志(标志几乎总是一个好主意).

使用gcc foo.c -Wextra我得到的程序编译你的程序:

foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
Run Code Online (Sandbox Code Playgroud)

奇怪的-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.
Run Code Online (Sandbox Code Playgroud)

并且对于原型问题,如上所述再次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
Run Code Online (Sandbox Code Playgroud)

或者在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.
Run Code Online (Sandbox Code Playgroud)