首页 文章

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

提问于
浏览 1849
383

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

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

#include <stdio.h>

int func();

int func(param)
{
    return param;
}

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

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

10 回答

  • 268

    C assumes int if no type is given on function return type and parameter list . 只有这个规则才能实现奇怪的事情 .

    函数定义如下所示 .

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

    如果它是你写的原型

    int func(int param);
    

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

    int func(int);
    

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

    int func(param);
    

    如果你走得更远,跟随也有效 .

    func();
    

    当您编写 func() 时,编译器会假定 int func() . 但是不要将 func() 放在函数体内 . 这将是一个函数调用

  • 158

    这是 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 */
    }
    
  • 55

    正如@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编译的例子:

    main.c

    main2.c

    main3.c

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

    像这样:

    int myfunc(int param);
    
  • 53

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

    使用_771409编译你的程序我得到:

    foo.c: In function ‘func’:
    foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
    

    奇怪的是 -Wextra 没有 grab 这个 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.
    
  • 29

    如果函数声明没有参数,即空,那么它将采用未指定数量的参数 . 如果你想让它不带参数,那么将它改为:

    int func(void);
    
  • 15

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

    cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
    

    这些标志强制执行以下几项操作:

    • -Wmissing-variable-declarations:如果不先获取原型,就不可能声明非静态函数 . 这使得头文件中的原型更有可能与实际定义匹配 . 或者,它强制您将static关键字添加到不需要公开显示的函数中 .

    • -Wstrict-variable-declarations:原型必须正确列出参数 .

    • -Wold-style-definition:函数定义本身也必须正确列出参数 .

    默认情况下,许多开源项目中也使用这些标志 . 例如,在Makefile中使用WARNS = 6构建时,FreeBSD启用了这些标志 .

  • 11
    • 空参数列表表示"any arguments",因此定义没有错误 .

    • 缺少的类型假定为 int .

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

  • 5

    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语言误导的人可能会感到畏缩,因为他们在尝试锻炼外语时需要输入额外的字符:-)

  • 3

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

  • 0

    所有其他答案都是正确的,但仅适用于completion

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

    再次为了完整起见 . From C11 specification 6:11:6(第179页)

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

相关问题