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

问题描述 投票:0回答:2

请看下面我的代码

#include <stdio.h>

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

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

  return 0;
}

我想应该是因为我调用了不存在的函数原型而出现错误。实际上,代码用 mingw5 编译器编译得很好,这对我来说很奇怪,然后我换成 Borland 编译器,我收到一条警告消息说不printOut 函数原型,这只是一个警告吗?更重要的是,代码执行良好,没有弹出任何错误窗口。

c function static
2个回答
6
投票

在 C 中,没有任何参数的函数仍然可以带参数。

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

void printOut(void)

这是正确的方法,但不太常见,尤其是对于那些具有 C++ 背景的人来说。


5
投票

你的程序的行为是未定义的,因为你定义

printOut()
时没有参数,但你用一个参数调用它。 你需要修复它。 但是您已经以编译器不需要诊断问题的方式编写了它。 (例如,gcc 不会警告参数不匹配,即使使用
-std=c99 -pedantic -Wall -Wextra
-O3。)

这是有历史原因的。

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

int plus_one();

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

int plus_one(n)
int n;
{
     return n + 1;
}

参数信息隐藏在定义中。

ANSI C 添加了原型,所以上面可以这样写:

int plus_one(int n);

int plus_one(int n)
{
    return n + 1;
}

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

在你的定义中:

void printOut()
{
    ...
}

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

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

void printOut(void)
{
    ...
}

这是用 C 语言编写它的唯一正确方法。

当然,如果您只是在程序中进行此更改,然后在

printOut()
中添加对
main()
的调用,您将面临无限递归循环。 您可能希望
printOUt()
接受
int
论证:

void printOut(int n)
{
    ...
}

事实上,C++ 有不同的规则。 C++ 源自 C,但不太关心向后兼容性。 当 Stroustrup 将原型添加到 C++ 时,他完全放弃了旧式声明。 由于无参数函数不需要特殊情况的

void
标记,因此 C++
 中的 
void printOut() 明确表示
printOut
没有参数,带参数的调用是错误的。 C++ 还允许
void printOut(void)
与 C 兼容,但这可能不经常使用(编写同时有效的 C 和有效的 C++ 代码很少有用。)C 和 C++ 是两种不同的语言;无论您使用哪种语言,您都应该遵守其规则。

© www.soinside.com 2019 - 2024. All rights reserved.