我有三个文件,test.c,foo.c,foo.h 在foo.c i
#include "foo.h"
在test.c i
#include "foo.c."
然后当我编译我的代码时,我使用gcc -o test test.c,然后编译。
然而,我的教授告诉我,我应该使用
#include "foo.h"
在我的test.c而不是#include foo.c
中,我应该这样编译
gcc -o test test.c foo.c
第二种方式更受欢迎吗?如果是,为什么?这两个编译有什么区别?
答案 0 :(得分:7)
在大多数情况下,您不应该包含源文件(除了您可能希望包含由单独脚本动态生成的一段代码的情况)。源文件将直接传递给编译器。只应包含头文件。
虽然您的教授建议的方式是正确的,但在这种情况下,以下方式具有更多的教育价值:
gcc -c test.c
gcc -c foo.c
gcc -o test foo.o test.o
前两行将每个源文件编译为一个目标文件,第三行并不真正编译,只调用链接器从2个目标文件中生成可执行文件。我们的想法是区分编译和链接,这将以教授建议的方式透明地执行。
答案 1 :(得分:2)
主要原因不是其他.c文件中的#include
.c文件:
避免重复定义错误:假设foo.c
定义函数foo()
。您还有两个使用foo()
的其他文件,因此两个文件都是#include "foo.c"
。当您尝试构建项目时,编译器将多次翻译foo.c
,这意味着它将看到多次尝试定义foo
函数,这将导致它发出诊断并停止。
最大限度地缩短构建时间:即使您没有引入重复的定义错误,也最终会不必要地重新编译相同的代码。假设您#include "foo.c"
中bar.c
,并且您发现需要在bar.c
中进行单行更改。重建时,最终会不必要地重新翻译foo.c
的内容。
C允许您相互单独编译源文件,然后将生成的目标文件链接在一起以构建应用程序或库。理想情况下,头文件应仅包含非定义对象声明,函数原型声明,类型定义和宏定义。
答案 2 :(得分:1)
通常的做法是#include
头文件而不是源文件,并单独编译源文件。关注点分离使得在大型项目中更容易使用。在您的示例中,它可能是微不足道的,但是当您有数百个文件可以使用时可能会造成混淆。
按照教授建议的方式进行操作意味着您可以单独编译每个来源。因此,如果您有一个大型项目,其中源代码为数千行代码,并且您在test.c
中更改了某些内容,则可以重新编译test.c
,而不必重新编译foo.c
它
希望这有道理:)
答案 3 :(得分:1)
如果要在gcc中编译多个文件,请使用:
gcc f1.c f2.c ... fn.c -o output_file
答案 4 :(得分:1)
简短回答:
是的,第二种方式更优选。
答案很长:
在这种特定情况下,您将得到相同的结果
要了解一个北斗星,首先需要知道“#include”语句基本上复制它包含的文件并将其值放在“#include”语句中。
因此“h”文件用于前向声明,你可以使用几个不同的文件
虽然“c”文件具有实现,但在这种情况下,如果两个文件都实现相同的功能,则链接它们时会出错
假设您将拥有“test2.c”,并且您还将包含foo.c并尝试将其与test.c链接。您将拥有两个foo.c实现。但是如果你只在所有3个文件(foo.c,test.c和test2.c)中包含foo.h,你仍然可以链接它们,因为foo.h不应该有任何实现。
答案 5 :(得分:1)
包含.c文件不是一个好习惯。
在你的情况下 在test.c和foo.c中包含foo.h,但在头文件中添加它
#ifndef foo.h
#define foo.h
..your header code here
#endif
以上述方式编写标题,确保您可以多次包含它,只是为了安全起见。
了解如何将代码放入文件>
在foo.h中
将所有全局结构和变量与函数原型一起放置,您将使用它。
在foo.c中
在此定义模块化功能
在test.c中
这里你通常有你的main(),你将调用并测试foo.c中定义的函数
您通常将所有文件放在同一个文件夹中,编译器会找到它们并单独编译它们,它们稍后会被链接器连接。
答案 6 :(得分:1)
gcc f1.c f2.c ... fn.c -o output_file