使用没有原型的旧样式函数的C编译器的行为

使用没有原型的旧样式函数的C编译器的行为,c,function,declaration,implicit,function-prototypes,C,Function,Declaration,Implicit,Function Prototypes,当我的程序由两个文件组成时: main.c #include <stdio.h> int main(void) { printf("%lf\n",f()); return 0; } #include <stdio.h> int main(void) { printf("%lf\n",f()); return 0; } double f(int a) { return 1; } 编译器不会显示任何错误

当我的程序由两个文件组成时:

main.c

#include <stdio.h>

int main(void) { 
     printf("%lf\n",f());   
     return 0;
 }
#include <stdio.h>

int main(void) { 
     printf("%lf\n",f());   
     return 0;
 }

double f(int a) {
 return 1;
}
编译器不会显示任何错误

当我的程序仅包含一个文件时:

$ cat func.c >>main.c
$ gcc -std=c99 -pedantic -W -Wall func.c main.c -o test
main.c:4: warning: implicit declaration of function 'f'
main.c: At top level:
main.c:9: error: conflicting types for 'f'
main.c:4: error: previous implicit declaration of 'f' was here
main.c:9: warning: unused parameter 'a'
main.c

#include <stdio.h>

int main(void) { 
     printf("%lf\n",f());   
     return 0;
 }
#include <stdio.h>

int main(void) { 
     printf("%lf\n",f());   
     return 0;
 }

double f(int a) {
 return 1;
}

有人能解释这种奇怪的行为吗?

C将假定函数的原型为int func();除非您另有说明。(注意,在C中int func()和int func(void);是不同的东西)

在第二种情况下,调用
f()
,编译器没有看到任何原型,因此它假定它是
intf()。稍后,它会看到您对具有不同原型的
f()
的定义,并发出一个错误


这种情况在1中不会发生。案例,因为它们在不同的编译单元中

您的第一个示例从未使用
func.c
,因此我不确定编译器对
f()
做了什么,因为它没有定义


在第二个示例中,我不知道为什么不能有两个具有不同签名的函数,但是您没有调用您定义的函数。调用
f()
时不带任何参数,但您定义的
f
接受一个int,这使它成为一个不同的函数。

两个程序都是错误的

在范围内没有原型的情况下,编译器假设函数返回
int
,并接受未指定数量的参数

让我们稍微更改一下您的文件:

$ cat func.c
double f(int a) {
    return 1.0;
}
$ cat main.c
#include <stdio.h>

int main(void) { 
    double d = f();
    printf("%lf\n", d);
    return 0;
}
它没有打印1,但打印了0。这是因为编译器假定
f()
返回一个
int
,赋值
d=f()
将“
int
”转换为
double
。编译器仍然编译代码,因为它无法判断
f()
的定义方式(隐式)与声明方式不同。但是编译上述程序不是标准所要求的,因此编译器可能会拒绝它(例如尝试使用
gcc-Werror

如果我们将所有内容都放在一个文件中:

$ cat func.c >>main.c
$ gcc -std=c99 -pedantic -W -Wall func.c main.c -o test
main.c:4: warning: implicit declaration of function 'f'
main.c: At top level:
main.c:9: error: conflicting types for 'f'
main.c:4: error: previous implicit declaration of 'f' was here
main.c:9: warning: unused parameter 'a'
现在编译器看到了冲突,并给出了一条错误消息。但是,编译器不需要拒绝上述程序,它可能拒绝,也可能不拒绝


大多数编译器不会拒绝第一个程序,因为他们不知道在另一个翻译单元中函数
f()
的定义是否正确。他们拒绝第二个程序,因为他们知道您没有。

我的理解是:在第一种情况下,链接器负责将函数调用与其定义绑定;在第二种情况下,编译器负责将函数的调用与其定义绑定。我说得对吗?