在程序中编译多个C文件

在程序中编译多个C文件,c,compilation,linker,C,Compilation,Linker,我有以下两个文件: file1.c int main(){ foo(); return 0; } void foo(){ } file2.c int main(){ foo(); return 0; } void foo(){ } 我是否可以编译并链接这两个文件,以便file1.c能够识别foo函数而不添加extern 更新了原型 gcc file1.c file2.c抛出:警告:函数foo的隐式声明 你可以,但你不应该 使用头文件file2.h: // file

我有以下两个文件:

file1.c

int main(){
  foo();
  return 0;
}
void foo(){

 }
file2.c

int main(){
  foo();
  return 0;
}
void foo(){

 }
我是否可以编译并链接这两个文件,以便
file1.c
能够识别
foo
函数而不添加
extern

更新了原型

gcc file1.c file2.c抛出:警告:函数foo的隐式声明

你可以,但你不应该

使用头文件file2.h:

// file2.h

void foo(); // prototype for function foo()
然后添加:

#include "file2.h" 
在file1.c中

汇编:

$ gcc -Wall file1.c file2.c -o foo

一般来说,使用头文件来定义每个模块的接口比使用依赖模块中的特殊原型更好(更健壮)。这有时被称为SPOT(单点真理)原则。

您不需要
extern
,但file1.c必须看到
foo()
存在的声明。通常,此声明位于头文件中

要添加转发声明而不使用头文件,只需将file1.c修改为:

int foo();  // add this declaration

int main(){
  foo();
  return 0;
}

正确的方法如下:

file1.c

#include <stdio.h>
#include "file2.h"

int main(void){
    printf("%s:%s:%d \n", __FILE__, __FUNCTION__, __LINE__);
    foo();
    return 0;
}
file2.c

#include <stdio.h>
#include "file2.h"

void foo(void) {
    printf("%s:%s:%d \n", __FILE__, __func__, __LINE__);
    return;
}

这很难看,但使用gcc,您可以:

gcc -include file2.c file1.c

-include
是预处理器的标志,它将在file1.c的最顶端包含file2.c的内容。话虽如此,这是一个糟糕的选择,除了最简单的程序外,其他所有程序都会出现故障。

gcc file1.c file2.c
,我也不知道c在没有看到原型时函数调用的确切规则,但您可能必须添加
int foo()以上
main
@Seth:在给出gcc示例时,请始终-包括
-Wall
-这有助于让noobs养成良好习惯。我更新了问题。我可以用-Wall来做。我可以不用任何头文件就把这两个文件编译在一起吗?你仍然需要一个
foo()
的转发声明,如果你愿意,可以在file1.c中这样做。@mary是的,头文件是为编译器准备的,但这是由链接完成的你不需要
extern
来调用函数,您只需要原型,比如
intfoo()file2.c
@Seth:true中的头和正文中使用code>,您不需要它,但是显式使用它并没有什么错。我从未见过有人仅仅因为函数
extern
在另一个文件中而使用它。如果不在原型上使用
extern
,就说您可以但不应该在另一个文件中编写函数是完全没有根据的,除非您知道一些我不知道的事情(这很可能)@Seth:一点也不知道-原型是
extern
,无论您是显式声明它
extern
,还是使用C的隐式规则。我把它放在那里是为了让noobs明白它是一个原型,但是现在大多数人都不使用显式的
extern
声明表单。那你为什么告诉他,如果不写
extern
,他就不应该写一个要在其他文件中使用的函数呢?此处的“不应该”一词太强C99预定义标识符为
\uuu func\uuu
。与gcc特定的
\uuuuu函数\uuuuuu
相比,我更喜欢这样。我认为这样将头传递给编译器不是一个好的做法-如果需要,预处理器会将其带进来。@TimothyJones,我很抱歉。这是一个很好的观点。谢谢你检查一下答案。。我现在已经改正了!另外,请始终在任何gcc命令行示例中包括
-Wall
。@minute:它告诉编译器启用所有警告-编译器警告非常有用和重要,特别是对于仍在学习该语言的人,但不幸的是,默认情况下没有启用,始终在启用警告的情况下编译,并注意编译器忽略的任何警告。