【问题标题】:Why do we need to include the C or CPP declaration files during compilation and not the default libraries like iostream?为什么我们需要在编译期间包含 C 或 CPP 声明文件,而不是像 iostream 这样的默认库?
【发布时间】:2017-09-14 20:59:06
【问题描述】:

如果CCPP 程序需要使用我们自己的带有声明的头文件和带有定义的cpp 文件进行编译,我们需要在编译命令中包含带有定义的cpp 文件(参见this answer)。但是,当我们写#include <iostream>时,我们并没有像g++ main.cpp iostream.cpp -o main那样在编译语句中包含iostream.cpp

如果我们编写自定义声明文件,例如带有类声明的hello.hpp和带有定义的hello.cpp,我们需要在main.cpp文件的标题中包含hello.hpp后使用g++ main.cpp hello.cpp -o main对其进行编译.这是为什么呢?

编辑:我们是否可以为我们的自定义头文件和 cpp 文件模仿标准模板库的行为,这样我们所要做的就是包含头文件和声明自动获取编译?如果是,那么如何?如果没有,为什么不呢?

【问题讨论】:

  • 链接器自动链接到默认运行时库,该库包含标准头文件中的所有函数。
  • STL 是大量模板化的,因此大部分 STL 的源代码都在头文件本身中。对于预编译的 STL 部分而不是在标头本身中,您的开发环境可能有一个默认配置,可以在链接期间自动拉入必要的库。
  • “为什么?”为了方便起见。
  • 相关(但不是完全重复的 IMO):stackoverflow.com/questions/25036467/…
  • @KerrekSB 来自wikipedia运行时环境实现了编程语言的执行模型、内置函数和其他基本行为。 诸如stdiomalloc 是 C 运行时的一部分。

标签: c++ c gcc


【解决方案1】:

标准库被隐式链接。所以

g++ main.cpp -o main

真的

g++ main.cpp -o main -lstdc++ -lc

其中libstdc++ 是c++ 标准库,libc 是c 标准库。其他库需要显式链接(例如libm)。

如果您将编译和链接步骤分开,这会变得更加清晰:

g++ -c main.cpp -o main.o
g++ -c other.cpp -o other.o
g++ main.o other.o /usr/lib/libstdc++.a /usr/lib/libc.a -o main

这里我们将我们的main()函数定义和其他定义(other.cpp)编译成目标文件,并将它们与标准库中现有的编译函数/类/变量定义结合起来。

Shared Library Creation 上查看 TLDP 页面和 Static Library Creation 了解有关如何将定义文件(.c.cpp)转换为库的详细信息。

【讨论】:

  • 已对问题进行了编辑,请您也看一下吗?
  • @SahilArora 不,编译器不会神奇地找到包含您的定义的库,位于您计算机的某个位置。您需要告诉他您的图书馆的路径,以便它可以链接它。虽然你可以把所有的东西都放在头文件中并将每个函数标记为内联,但是编译时间会随着你放在头文件中的东西而爆炸。
【解决方案2】:

首先,检查在this post 中包含<filename>"filename" 之间的区别:

对于#include "filename",预处理器在与包含指令的文件相同的目录中搜索。这种方法是 通常用于包含程序员定义的头文件。

对于#include ,预处理器在实现中搜索 依赖方式,通常在由预先指定的搜索目录中 编译器/IDE。此方法通常用于包含标准库 头文件

您包含一个文件这一事实并不意味着您正在编译一个文件。实际上,通过包含您正在解决对包含文件的语法引用,例如类声明(在 C++ 中)、公共变量、结构、枚举和函数调用。这将避免您的代码出现未引用对象错误,从而破坏编译过程。

使用这些引用编译您的代码并不意味着编译了原始引用的代码。举个例子:

mycode.cpp 包括myclass.hpp,如:

#include "myclass.hpp"

如果引用正确,您可以使用以下命令进行编译:

g++ mycode.cpp 

您将获得mycode.cpp 的编译代码(一个名为mycode.o 的目标文件),而不是myclass 的编译代码。 mycode.cpp 正确编译,因为它具有对 myclass 对象/函数/等的引用,但这并不意味着 myclass 已编译(您还没有目标文件 myclass.o)。

如果您链接编辑mycode.cpp,将缺少几个引用,因为没有myclass 编译代码。

如果您选择:

g++ mycode.cpp myclass.cpp 

它将为mycode.omyclass.o 生成目标文件,以后可以将它们链接在一起。

在 STL 库的情况下,您只需要引用,因为它们已经编译并且可以在所谓的标准库中使用(一组对象 .o 已经为您编译的文件)。喜欢的人会自动或在您正确地告诉他这样做的情况下将它们连接在一起。

我建议您通过 compilation -> object files -> link editing -> executable file 流程来了解这些步骤,这仅适用于编译语言。

【讨论】:

    【解决方案3】:

    您需要了解编译器会读取输入文件,然后对其进行预处理,并且预处理器会替换所有 #include 语句,因此编译器本身永远不会看到它们。就真正的编译器而言,没有#include 语句。然后编译器将源语言转换为机器代码。编译器为每个输入(c 或 cpp)文件编写一个目标文件。目标文件中的机器码不能直接执行;它必须与其他代码链接。

    最初,程序员会将他们的程序与已经编译到目标文件库中的其他目标文件链接。多个目标文件被静态链接在一起以生成一个可执行文件,并且可以为许多可执行文件完成。所以换句话说,许多目标文件中的每一个都可能存在很多次,对于许多可执行文件中的每一个都可能存在一次。这意味着当某些事情发生变化时,有时必须再次链接许多使用相同目标文件的程序。后来程序员了解到动态链接到目标文件很有帮助,这就是动态链接库。

    当你编译你的程序时,编译器包括链接器的指令以链接到其他库,主要是“C运行时”(CRT)。该链接可以是静态链接或动态链接。此外,标题还提供有关 CRT 的信息。大多数标准库(std 命名空间)实际上都在标头中,例如在“iostream”中,并与您的程序一起编译。任何不在标头中的内容都在某个 CRT 库中。

    因此,可能是 iostream.cpp 的等价物要么在您自己的程序中,例如 main.cpp,要么已经编译并在与您的程序链接的 CRT 库中。

    【讨论】:

      猜你喜欢
      • 2013-05-10
      • 2012-10-11
      • 2014-03-15
      • 2013-10-27
      • 2015-07-22
      • 1970-01-01
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多