c函数原型不匹配只是一个警告

Tra*_*acy 3 c compiler-construction static function

请看下面的代码

#include <stdio.h>

void printOut()
{
 static int i = 0;
 if (i < 10)
 {
  printOut(i);
 }
}

int main(int argc, char *argv[])
{

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我猜应该有一个错误,因为我调用了不存在的函数prototype.Actually,代码编译好mingw5编译器,这对我来说很奇怪,然后我改为Borland编译器,我收到一条警告消息说没有printOut功能原型,这只是一个警告吗?更重要的是,代码执行良好,没有任何弹出错误窗口.

Mys*_*ial 6

在C中,没有任何参数的函数仍然可以获取参数.

这就是它编译的原因.指定它不带任何参数的方法是:

void printOut(void)
Run Code Online (Sandbox Code Playgroud)

这是正确的方法,但不常见,特别是对于那些来自C++背景的人.

  • 事实并非那么简单.只有当**定义**并且```作为最后一个参数时,函数才能获取可变数量的参数. (2认同)
  • 我不同意*正确的*`(void)`形式在任何意义上都是"不太常见".在C*中编写时编写`void printOut()`而不是`void printOut(void)`*的C++程序员只是做错了.C和C++有不同的规则,因为它们是不同的语言.用`()`声明的C函数确实*不*取可变数量的参数; 它采用定义中指定的参数的确切数量和类型.声明中缺少的信息只会阻止编译器诊断错误的调用.*始终*使用原型. (2认同)

Kei*_*son 5

您的程序的行为是未定义的,因为您printOut()没有参数定义,但您使用一个参数调用它.你需要解决它.但是你编写它的方式不需要编译器来诊断问题.(例如,gcc不会警告参数不匹配,即使使用-std=c99 -pedantic -Wall -Wextra-O3也是如此.)

其原因是历史性的.

预ANSI C(1989年之前)没有原型; 函数声明无法指定预期的参数类型或数量.另一方面,函数定义指定了函数的参数,但不是编译器可以用来诊断不匹配的调用的方式.例如,可以声明具有一个int参数的函数(例如,在头文件中),如下所示:

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

并定义(例如,在相应的.c文件中),如下所示:

int plus_one(n)
int n;
{
     return n + 1;
}
Run Code Online (Sandbox Code Playgroud)

参数信息隐藏在定义中.

ANSI C添加了原型,因此上面的内容可以写成:

int plus_one(int n);

int plus_one(int n)
{
    return n + 1;
}
Run Code Online (Sandbox Code Playgroud)

但该语言继续支持旧式声明和定义,以免破坏现有代码.即使即将推出的C201X标准仍然允许ANSI之前的功能声明和定义,尽管它们已经淘汰了22年.

在你的定义中:

void printOut()
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

你正在使用旧式函数定义.它说printOut没有参数 - 但如果你不正确地调用它,它不会让编译器发出警告.在函数内部,您可以使用一个参数调用它.此调用的行为未定义.它可以悄悄地忽略这个无关紧要的论点 - 或者它可能会破坏堆栈并导致你的程序死得很厉害.(后者不太可能;由于历史原因,大多数C调用约定都容忍此类错误.)

如果您希望printOut()函数没有参数,并且您希望编译器在错误地调用它时进行投诉,请将其定义为:

void printOut(void)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

这是用C编写它的唯一正确方法.

当然,如果您只是在程序中进行此更改然后添加对printOut()in 的调用main(),那么您将拥有无限递归循环.你可能想要printOUt()一个int参数:

void printOut(int n)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

碰巧,C++有不同的规则.C++源自C,但对后向兼容性的关注较少.当Stroustrup将原型添加到C++时,他完全放弃了旧式声明.由于不需要无void参数函数的特殊情况标记,因此void printOut() 在C++中明确表示printOut没有参数,并且带参数的调用是错误.C++也允许void printOut(void)与C兼容,但这可能不经常使用(编写有效C和有效C++的代码很少有用.)C和C++是两种不同的语言; 您应该遵循您使用的任何语言的规则.