这是一个基本的C代码,根据我应该抛出三个错误(函数没有定义,函数没有返回任何东西,函数参数丢失)。但令我惊讶的是它没有扔掉任何东西,它编译并给出了一些垃圾结果:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int a=f1();
printf("a %d\n",a);
system("PAUSE");
return 0;
}
f1(int *t)
{
printf("t %d", t);
}
PS:我在Windows上使用gcc编译器。
答案 0 :(得分:4)
在C中,当未声明函数时,假定返回int
并继续编译(btw this can lead to nasty bugs)。如果声明函数没有类型(因为f1()
在您的代码中,则假定它返回int
。不从非void函数返回值(如在代码中)是未定义的行为。
因此,您提到的所有要点都不会导致编译错误。不需要未定义的行为来阻止程序运行 - 程序可能会运行,甚至可能产生漂亮的结果。
答案 1 :(得分:2)
首先,您没有启用警告进行编译。您通常应该至少使用-Wall
开关调用gcc - 对于您的示例代码,它会给出:
x.c: In function 'main':
x.c:7: warning: implicit declaration of function 'f1'
x.c: At top level:
x.c:15: warning: return type defaults to 'int'
x.c: In function 'f1':
x.c:16: warning: format '%d' expects type 'int', but argument 2 has type 'int *'
x.c:17: warning: control reaches end of non-void function
其次,它编译的原因是它中的所有错误都是一种称为“未定义行为”的形式,这意味着编译器不是 required 来诊断它们并停止编译 - 它可以简单地产生垃圾结果。
答案 2 :(得分:2)
如果您使用gcc的-Wall
选项启用所有警告,您可能会更高兴。然后你会在编译时看到这个:
C:\test>make
gcc -Wall prog.c -o prog
prog.c: In function 'main':
prog.c:7:5: warning: implicit declaration of function 'f1'
prog.c: At top level:
prog.c:14:1: warning: return type defaults to 'int'
prog.c: In function 'f1':
prog.c:16:8: warning: format '%d' expects type 'int', but argument 2 has type 'int *'
prog.c:17:1: warning: control reaches end of non-void function
您还可以使用-Werror
将所有警告转为错误(因此您不得不修复它们)。
答案 3 :(得分:1)
尝试使用-Wall
标志再次进行编译。这会打开所有警告,然后你会看到很多:
c.c: In function ‘main’:
c.c:7: warning: implicit declaration of function ‘f1’
c.c: At top level:
c.c:15: warning: return type defaults to ‘int’
c.c: In function ‘f1’:
c.c:16: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘int *’
c.c:17: warning: control reaches end of non-void function
由于您没有任何编译时错误,只有警告,因此代码编译良好。它只是不会很好地执行。
答案 4 :(得分:1)
f1被认为具有隐式原型'int f1(int)'。 因此呼叫有效。 f1不返回任何内容,而隐式支持返回int:行为未定义。 编译器可能会警告您隐式原型与定义不一致。它也可以要求适当的回报。这是编译器内部静态分析可以执行的检查的一部分:gcc不执行此操作,其他人可能执行此操作。 无论如何,编译器通常不保证任何有关非ISO符合性程序的内容。
答案 5 :(得分:0)
如果您在gcc命令中添加-Wall
,则会收到一些警告。我猜它有效,因为旧式C具有松散的功能原型。并假设未知函数返回int
。链接器工作,因为没有未定义的符号(f1
存在),但你得到垃圾,因为堆栈上传递的内容(即什么都没有)不是预期的。