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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13950642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:47:41  来源:igfitidea点击:

Why does a function with no parameters (compared to the actual function definition) compile?

cparametersfunction-prototypesfunction-parameter

提问by AdmiralJonB

I've just come across someone's C code that I'm confused as to why it is compiling. There are two points I don't understand.

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

First, the function prototype has no parameters compared to the actual function definition. Second, the parameter in the function definition does not have a type.

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

#include <stdio.h>

int func();

int func(param)
{
    return param;
}

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

Why does this work? I have tested it in a couple of compilers, and it works fine.

为什么这样做?我已经在几个编译器中对其进行了测试,并且运行良好。

采纳答案by Krishnabhadra

All the other answers are correct, but just for completion

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

A function is declared in the following manner:

  return-type function-name(parameter-list,...) { body... }

return-typeis 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-nameis the name of the function.

parameter-listis 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.

函数的声明方式如下:

  return-type function-name(parameter-list,...) { body... }

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

function-name函数的名称

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

And again for the sake of completeness. From C11 specification 6:11:6(page: 179)

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

The use of function declarators with empty parentheses(not prototype-format parameter type declarators) is an obsolescent feature.

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

回答by Tony The Lion

In C func()means that you can pass any number of arguments. If you want no arguments then you have to declare as func(void). The type you're passing to your function, if not specified defaults to int.

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

回答by Jens

int func();is an obsolescent function declaration from the days when there was no C standard, i.e. the days of K&R C(before 1989, the year the first "ANSI C" standard was published).

int func();是从没有 C 标准的日子开始的过时函数声明,即K&R C的日子(1989 年之前,即第一个“ANSI C”标准发布的年份)。

Remember that there were no prototypes in K&R Cand the keyword voidwas not yet invented. All you could do was to tell the compiler about the return typeof a function. The empty parameter list in K&R C means "an unspecified but fixed" number of arguments. Fixed means that you must call the function with the samenumber of args each time (as opposed to a variadicfunction like printf, where the number and type can vary for each call).

请记住,K&R C没有原型,关键字void还没有发明。你所能做的就是告诉编译器一个函数的返回类型。K&R C 中的空参数列表意味着“未指定但固定”数量的参数。Fixed 意味着您每次必须使用相同数量的 args调用该函数(而不是像 那样的可变参数函数printf,每次调用的数量和类型都可能不同)。

Many compilers will diagnose this construct; in particular gcc -Wstrict-prototypeswill tell you "function declaration isn't a prototype", which is spot on, because it lookslike a prototype (especially if you are poisoned by C++!), but isn't. It's an old style K&R C return type declaration.

许多编译器会诊断这个结构;特别gcc -Wstrict-prototypes会告诉你“函数声明不是原型”,这是正确的,因为它看起来像一个原型(特别是如果你被 C++ 毒害了!),但不是。这是一个旧式的 K&R C 返回类型声明。

Rule of thumb:Never leave an empty parameter list declaration empty, use int func(void)to be specific. This turns the K&R return type declaration into a proper C89 prototype. Compilers are happy, developers are happy, static checkers are happy. Those mislead by^W^Wfond of C++ may cringe, though, because they need to type extra characters when they try to exercise their foreign language skills :-)

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

回答by unwind

  • The empty parameter list means "any arguments", so the definition isn't wrong.
  • The missing type is assumed to be int.
  • 空参数列表意味着“任何参数”,所以定义没有错。
  • 假定缺少的类型是int

I would consider any build that passes this to be lacking in configured warning/error level though, there's no point in being this allowing for actual code.

我会认为任何通过这个的构建都缺乏配置的警告/错误级别,但允许实际代码没有意义。

回答by Lei Mou

It's K&Rstyle function declaration and definition. From C99 Standard (ISO/IEC 9899:TC3)

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

Section 6.7.5.3 Function Declarators (including prototypes)

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

An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied. (If both function types are "old style", parameter types are not compared.)

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

Section 6.11.6 Function declarators

第 6.11.6 节函数声明符

The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

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

Section 6.11.7 Function definitions

第 6.11.7 节函数定义

The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature.

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

Which the old style means K&Rstyle

旧风格意味着K&R风格

Example:

例子:

Declaration: int old_style();

宣言: int old_style();

Definition:

定义:

int old_style(a, b)
    int a; 
    int b;
{
     /* something to do */
}

回答by Shiplu Mokaddim

C assumes intif no type is given on function return type and parameter list. Only for this rule following weird things are possible.

C 假设int在函数返回类型和参数列表上没有给出类型。只有遵循奇怪的事情的这条规则才是可能的。

A function definition looks like this.

函数定义如下所示。

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

If its a prototype you write

如果它是你写的原型

int func(int param);

In prototype you can only specify the type of parameters. Parameters' name is not mandatory. So

在原型中,您只能指定参数的类型。参数的名称不是强制性的。所以

int func(int);

Also if you dont specify parameter type but name intis assumed as type.

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

int func(param);

If you go farther, following works too.

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

func();

Compiler assumes int func()when you write func(). But dont put func()inside a function body. That'll be a function call

编译器假定int func()您在编写func(). 但不要放在func()函数体内。那将是一个函数调用

回答by RTOSkit

As stated @Krishnabhadra, all previous responses from other users, have a correct interpretation, and I just want to make a more detailed analysis of some points.

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

In the Old-C as in ANSI-C the "untyped formal parameter", take the dimencion of your work register or instruction depth capability (shadow registers or instruction cumulative cycle), in an 8bit MPU, will be an int16, in a 16bit MPU and so will be an int16 an so on, in the case 64bit architectures may choose to compile options like: -m32.

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

Although it seems simpler implementation at high level, For pass multiple parameters, the work of the programmer in the control dimencion data type step, becomes more demanding.

虽然在高层看起来实现起来更简单,但对于传递多个参数,程序员在控制维度数据类型步骤的工作变得更加苛刻。

In other cases, for some microprocessors architectures, the ANSI compilers customized, leveraged some of this old features to optimize the use of the code, forcing the location of these "untyped formal parameters" to work within or outside the work register, today you get almost the same with the use of "volatile" and "register".

在其他情况下,对于一些微处理器架构,ANSI 编译器定制,利用一些旧的特性来优化代码的使用,迫使这些“非类型化形式参数”的位置在工作寄存器内部或外部工作,今天你得到与使用“volatile”和“register”几乎相同。

But it should be noted that the most modern compilers, not make any distinction between the two types of parameters declaration.

但应该注意的是,最现代的编译器,不会对两种类型的参数声明做任何区分。

Examples of a compilation with gcc under linux:

linux下gcc编译示例:

main.c

主文件

main2.c

main2.c

main3.c?
In any case the statement of the prototype locally is of no use, because there is no call without parameters reference to this prototype will be remiss. If you use the system with "untyped formal parameter", for an external call, proceed to generate a declarative prototype data type.

main3.c?
无论如何,在本地声明原型是没有用的,因为没有调用没有参数引用这个原型将被遗漏。如果使用带有“无类型形式参数”的系统,对于外部调用,继续生成声明性原型数据类型。

Like this:

像这样:

int myfunc(int param);

回答by none

Regarding parameter type, there are already correct answers here but if you want to hear it from the compiler you can try adding some flags (flags are almost always a good idea anyways).

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

compiling your program using gcc foo.c -WextraI get:

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

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

strangely -Wextradoesn't catch this for clang(it doesn't recognize -Wmissing-parameter-typefor some reason, maybe for historical ones mentioned above) but -pedanticdoes:

奇怪的-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.

And for prototype issue as said again above int func()refers to arbitrary parameters unless you exclicitly define it as int func(void)which would then give you the errors as expected:

对于上面再次提到的原型问题,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

or in clangas:

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.

回答by P.P

If the function declaration has no parameters i.e. empty then it is taking unspecified number of arguments. If you want to make it take no arguments then change it to:

如果函数声明没有参数,即为空,则它采用未指定数量的参数。如果您想让它不带任何参数,请将其更改为:

int func(void);

回答by Ed Schouten

This is why I typically advise people to compile their code with:

这就是为什么我通常建议人们编译他们的代码:

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

These flags enforce a couple of things:

这些标志强制执行以下几件事:

  • -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.
  • -Wmissing-variable-declarations:如果不先获得原型,就不可能声明非静态函数。这使得头文件中的原型更有可能与实际定义匹配。或者,它强制您将 static 关键字添加到不需要公开可见的函数中。
  • -Wstrict-variable-declarations:原型必须正确列出参数。
  • -Wold-style-definition:函数定义本身也必须正确列出参数。

These flags are also used by default in a lot of Open Source projects. For example, FreeBSD has these flags enabled when building with WARNS=6 in your Makefile.

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