如果您没有收到该代码的任何警告,那是因为您的编译器没有执行 C99 规则(调用printf
或任何函数,没有可见的声明是违反约束的)。通过将正确的选项传递给编译器,您可能至少会收到一些警告。如果您使用 gcc,请尝试gcc -std=c99 -pedantic -Wall -Wextra
.
所谓的 K&R C,即 1978 年第一版 Kernighan 和 Ritchie 的经典著作The C Programming Language所描述的语言,没有函数原型。(原型是一个函数声明,它指定了它的参数类型。)一个函数定义仍然必须定义它的参数(可能是隐式的),但是一个声明没有——并且典型的编译器没有检查参数的正确匹配(在函数调用)到参数(在函数定义中)。
如果您调用具有错误数量和/或类型的参数的函数会发生什么并不完全清楚。用现代术语来说,这是未定义的行为,但较旧的编译器通常会让你玩花样。
1989 年的 ANSI C 标准(重新发布为 1990 年 ISO C 标准)引入了原型(从早期的 C++ 中借用),但没有要求它们。但它确实明确指出,使用错误数量或类型的参数调用函数会导致未定义的行为;编译器不需要警告你,但是当你运行它时,程序可以做任何事情。
1999 年的 ISO C 标准删除了“隐式 int”规则,并规定在没有可见声明的情况下调用函数是非法的(违反约束)——但它仍然允许旧式函数声明和定义。所以在 K&R1 和 C89/C90 规则下,你的函数定义:
int func(param111)
{
printf("%d\n", param111);
return param111;
}
是有效的,并且param111
是类型int
。在 C99 规则下,它是无效的,但是:
int func(param111)
int param111;
{
printf("%d\n", param111);
return param111;
}
仍然合法(即使在 2011 年标准下仍然合法)。
从 C99 和 C11 开始,如果您调用可见声明不是原型的函数,则完全取决于您是否正确设置参数;如果你弄错了,编译器不需要警告你。
这就是为什么您应该始终对所有函数声明和定义使用原型。如今,几乎不存在编写使用前 ANSI 编译器编译的代码的需要。很难找到至少不支持 C89/C90 的编译器。
哦,你需要添加
#include <stdio.h>
到源文件的顶部,因为您正在调用printf
. 在 C89/C90 规则下,printf
没有可见声明的调用具有未定义的行为(因为printf
采用可变数量的参数)。在 C99 及更高版本下,这是违反约束的,需要编译时诊断。
我一直在挑剔缺少的参数声明。您的程序的一个稍微改变的变体:
#include <stdio.h> /* add this line */
int func(param111)
int param111; /* add this line */
{
printf("%d\n", param111);
return param111;
}
int main(void) /* add "void" */
{
int bla0 = func(99);
int bla1 = func(10,99);
int bla2 = func(11111110,99,10001);
printf("%d, %d, %d\n", bla0, bla1, bla2);
}
不违反任何需要在 C90、C99 或 C11 中进行编译时诊断的规则——但第二次和第三次调用func
具有未定义的行为。
请注意,编译器实际上有足够的信息来警告您您的调用func
不正确。刚刚看到 的定义func
,它应该知道,任何没有传递完全 1 个可隐式转换为的类型的参数的调用int
都是无效的。不需要警告,但编译器总是可以打印他们喜欢的任何额外警告。显然 gcc 的作者(以及您正在使用的任何编译器)认为不值得努力警告对具有旧式声明和/或定义的函数的不匹配调用。