【问题标题】:Which way should I compile my C code?我应该以哪种方式编译我的 C 代码?
【发布时间】:2013-02-14 21:26:14
【问题描述】:

我有三个文件,test.c、foo.c、foo.h。
在 foo.c 我

#include "foo.h"

在 test.ci 中

#include "foo.c."  

然后当我编译我的代码时,我使用 gcc -o test test.c,它会编译。

但是,我的教授告诉我,我应该使用

#include "foo.h" 

在我的 test.c 中而不是 #include foo.c,我应该这样编译它

gcc -o test test.c foo.c

第二种方式更受欢迎吗?如果是,为什么?这两种编译有什么区别?

【问题讨论】:

  • 简单就是试试:make 命令
  • 但我想了解 make 下发生了什么。学习 C 之类的低级语言不就是目的吗?
  • 没有make 实用程序用于编译源代码(任何语言)。

标签: c gcc compilation


【解决方案1】:

在大多数情况下,您永远不应该包含源文件(除了您可能希望包含由单独脚本动态生成的一段代码的情况)。源文件将直接传递给编译器。只应包含头文件。

虽然你的教授建议的方式是正确的,但在这种情况下,以下方式更具教育价值:

gcc -c test.c
gcc -c foo.c
gcc -o test foo.o test.o

前两行将每个源文件编译为一个目标文件,第三行并没有真正编译,只是调用链接器从两个目标文件中生成一个可执行文件。我们的想法是区分编译链接,这将按照教授建议的方式透明地执行。

【讨论】:

  • 这个问题被标记为 c 而不是 c++。
  • “gcc -o foo.o test.o 会产生什么?”小心使用 -o 标志 ...这会将可执行文件放入 foo.o,这是一个错误(如果链接成功,它不会因为它需要 foo.o 作为输入)。
  • “你必须在头文件中包含 CXX 文件或将实现直接写入头文件”——与 C 问题无关,但将模板实现放入扩展名为 .cxx 的文件中,然后包括那仍然将实现直接写入标头,但命名错误。重点仍然存在:仅包含头文件,而不包含源文件……即使在带有模板的 C++ 中也是如此。
  • @phoeagon,你从不 #include .c.cxx 文件。模板在标头中定义(并且这些模板不带有当今 C++ 风格的扩展)。
  • @octref,按照古老的约定,如果你调用编译器来链接一个可执行文件并且不给它命名,它就会被称为a.out
【解决方案2】:

通常的做法是#include 头文件而不是源文件,并单独编译源文件。关注点分离使得在大型项目中工作更容易。在您的示例中,这可能是微不足道的,但当您有数百个文件要处理时可能会令人困惑。

按照教授建议的方式进行操作意味着您可以分别编译每个源代码。因此,如果您有一个大型项目,其中源代码包含数千行代码,并且您更改了 test.c 中的某些内容,则只需重新编译 test.c 而不必同时重新编译 foo.c

希望这有点道理:)

【讨论】:

    【解决方案3】:

    如果要在 gcc 中编译多个文件,请使用:

    gcc f1.c f2.c ... fn.c -o output_file
    

    【讨论】:

      【解决方案4】:

      简答:
      是的,第二种方式更受欢迎。

      长答案:
      在这种特定情况下,您将获得相同的结果。
      要想有一个深入的了解,您首先需要知道“#include”语句基本上是复制它所包含的文件并放置它的值而不是“#include”语句。
      因此,“h”文件用于前向声明,您没有问题将包含几个不同的文件。
      虽然“c”文件具有实现,但在这种情况下,如果两个文件都实现相同的功能,则链接它们时会出错。
      假设您将拥有“test2.c”,并且还将包含 foo.c 并尝试将其与 test.c 链接,您将拥有 foo.c 的两个实现。但是如果你只在所有 3 个文件(foo.c、test.c 和 test2.c)中包含 foo.h,你仍然可以链接它们,因为 foo.h 不应该有任何实现。

      【讨论】:

        【解决方案5】:

        包含 .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】:

          在其他 .c 文件中不使用 #include .c 文件的主要原因是:

          • 避免重复定义错误:假设foo.c 定义了函数foo()。您还有另外两个使用foo() 的文件,因此您在这两个文件中都使用了#include "foo.c"。当您尝试构建项目时,编译器将多次转换foo.c,这意味着它将看到多次尝试定义foo 函数,这将导致它发出诊断并停止。

          • 最小化构建时间:即使不引入重复定义错误,最终也会不必要地重新编译相同的代码。假设您在bar.c 中使用#include "foo.c",并且您发现需要在bar.c 中进行一行更改。当你重建时,你最终会重新翻译foo.c 的内容不必要

          C 允许您将源文件彼此分开编译,然后将生成的目标文件链接在一起以构建您的应用程序或库。理想情况下,头文件应该只包含非定义对象声明、函数原型声明、类型定义和宏定义。

          【讨论】:

            【解决方案7】:
            gcc f1.c f2.c ... fn.c -o output_file
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-12-07
              • 2015-10-09
              • 1970-01-01
              • 2016-04-18
              • 1970-01-01
              • 1970-01-01
              • 2014-04-19
              相关资源
              最近更新 更多