【问题标题】:Why is compiling user defined files necessary? C++为什么需要编译用户定义的文件? C++
【发布时间】:2019-12-31 04:37:01
【问题描述】:

在执行预处理器指令#include <iostream> 时,发生的情况类似于将文本包含(如复制和粘贴)到main.cpp 中,您可以使用g++ main.cpp 进行编译。你不编译iostream.cpp

但是用户定义的文件呢? #include "userfile.h" 应该在 main.cpp 中包含类似的文本。那么如果 main 包含所有必要的代码,为什么我必须编译这两个文件(g++ main.cpp userfile.cpp)?

【问题讨论】:

  • "所有必要的代码"——注意你#includeuserfile.h,但是编译userfile.cpp。它们是不同的文件这一事实说明了为什么这种说法是不正确的。
  • @KenWayneVanderLinde 无论如何都不是 C 中带有 .h 的标准库头文件吗?
  • 标准库实现代码是:完全在头文件中实现并在您包含它们时与您的用户代码一起编译,或者已经编译成只需要链接的目标文件。
  • 是的,头文件以.h 结尾是正常的,但这不是重点。既然我现在有一点时间,我会写一个正确的答案。
  • 现在我也很震惊,因为我误解了这个问题。希望我的回答更准确。

标签: c++ compilation g++


【解决方案1】:

iostream 这样的“系统库”和用户提供的库之间并没有什么不同除了编译器会(为方便起见)在处理系统时隐含一些东西图书馆。在这种情况下,它隐式链接到其默认的标准库实现。

为了进一步扩展,让我们看看您对g++ 的第一次调用:

g++ main.cpp

由于g++ 的默认标准库实现称为libstdc++,您可以想象这是以下的简写:

g++ -lstdc++ main.cpp

(实际上可能涉及更多的诡计,所以我不保证这个扩展的命令会按原样工作。)

以防万一您还不熟悉链接...

当您编译.cpp 时,编译器 会生成一个目标文件(通常以.o 结尾)。当您有多个 .cpp 文件时,每个文件都会编译为单独的目标文件。然后它们必须以某种方式合并以生成最终的可执行文件。这种合并称为链接,由链接器完成。链接器的工作基本上是匹配不同目标文件中的名称,并输出一个可执行文件。

不过,这太简单了。最终结果不必是可执行文件,也可以是。 (我现在将坚持使用静态库,因为我认为它更简单)库是根据这种模式的文件名:lib*.a。无法执行库。相反,库只是一种方便的方式,可以将许多 .cpp 中的一堆功能打包成以后易于使用的形式。您可以将库与您自己的目标文件链接,以生成具有库中的功能以及您自己的代码的可执行文件。

在 libstdc++ 的示例中,如果我们假设您的系统有一个静态库,那将是一个名为 libstdc++.a 的文件。链接时,我们去掉前面的lib 和后面的.a(因为所有库都会有这个),只写stdc++。这就是我们将-lstdc++ 传递给g++ 的原因。

库的一个问题(如果我可以这么说的话)是它们对编译器没有任何意义,只对链接器有任何意义。为了使用库,你的源代码需要#include对应的头文件,这样编译器才能看到里面的定义/声明。

【讨论】:

  • 所以编译器隐式添加了一个额外的命令来编译标准库中包含的文件? "g++ -lstdc++ main.cpp" 与 "-lstdc++" 与类似 "g++ main.cpp iostream.cpp" 的效果相同?
  • 差不多了。我将添加更多细节。
  • @csguy 除了对我的答案进行编辑外,我还会在此处添加一条注释,以防不清楚:头文件 (.h) 和源文件 (.cpp)不必是一对一的,从技术上讲,库可以以多种不同的方式构建。因此,虽然您可以认为它等同于g++ main.cpp iostream.cpp (plus more .cpp files),但请记住,您通常不知道用于创建库的文件。图书馆只是一种不知从何而来的行为。
  • @csguy 有用的额外阅读:How does the compilation/linking process work?
【解决方案2】:

首先,编译速度,这是编译语言如 C 和 C++ 的繁琐部分。如果你不碰它,你不需要重新编译(一个缓慢的过程)myclass.cpp。你只需重新编译main.cpp,如果那是你的修改所在。不要在两个文件程序中考虑......考虑更大的程序。 (我工作的代码库大约有 100K 行——因为它是一个嵌入式系统,所以它很小——完整编译需要 5-8 分钟;你不能等待每一个微小的变化。

此外,它使其更加模块化,这意味着您只需编译一次文件,即使被两个不同的程序使用也是如此。如果您有一个通过网络发送MyClass 对象的客户端-服务器,则两者都需要myclass.cppmyclass.o 已编译)。

您还可以“隐藏”一些细节(特别是在没有 private 说明符的 C 语言中,或者在使用 PIMPL 语言的 C++ 中),因为这些细节隐藏在 cpp 文件中。

另外,在一个非常大的项目中,我不知道编译器是否可以管理这么多的元素(认为它必须有包含所有名称和标识符的表)。

既然如此,你为什么不把所有东西都放在main.cpp

请注意,SQLite 使用这种方法来提供它的“合并”编译,它将所有文件合并到一个文件中进行编译,这使得它更短一些,因为编译器更清楚那些宁愿隐藏起来。

【讨论】:

    猜你喜欢
    • 2014-03-15
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 2017-08-30
    相关资源
    最近更新 更多