我正在努力了解预处理,编译和链接

时间:2018-06-21 08:17:44

标签: c++ compilation preprocessor

我正在读一本叫做《跳入C ++》的书,书中有一部分写着:

例如,诸如

的语句
#include <iostream>

告诉预处理器将文件iostream的文本直接捕获到当前文件中。每次包含头文件时,它实际上都会被粘贴到文件中,然后编译器才能看到它,并且#include指令将被删除。

因此,据我了解,所有文件都粘贴到一个文件中,因此只剩下一个源文件。但是随后他继续说:

每个源文件都是单独编译的,这意味着目标文件仅包含针对已编译源代码的机器语言。

这表明当进入编译阶段时,源文件仍然是分开的,但是我认为所有文件都已粘贴到一个大文件中。有人可以解释一下,是将所有文件粘贴到一个文件中,还是将它们分开放置,然后再由链接器连接?

3 个答案:

答案 0 :(得分:1)

您的最后一点是正确的。 (以下文件结尾对于Linux系统是正确的)

在预处理器完成其工作之后,编译器将每个源文件(.cpp)编译为一个单独的目标文件(.o)。

然后,链接器将它们放到可执行文件,共享库(.so)或静态库(.a)中。

有关更多信息,请查看此问题:How does the compilation/linking process work?

答案 1 :(得分:1)

在C ++中,我们将头文件(.h或.hpp)和代码文件(.cpp)分开 通常在头文件中定义对象结构,并在代码中编写代码以实现其逻辑。

通常在代码文件的顶部包含一组标头

#include <iostream>
#incluie <string>

预处理器将获取这些标头中定义的类的定义,并创建一个包含所有定义的大文件。

代码文件本身将被单独编译为单个.o文件

例如:

song.h

#include <string>

class Song {
   public:
      std::string getLyrics();
};

person.h

#include "song.h"  // Since person sing a Song

class Person {
   public:
      void sing(Song song);
};

因此,在这种情况下,如果您在代码中执行此操作

main.cpp

#include "person.h"

int main() {
    Person person;
    Song song;

    person.sing(song);
}

预处理器会将您的main.cpp与标头组合成一个大文件。 这就是编译器将看到的。

class string { ...}

class Song {
   public:
      std::string getLyrics();
};

class Person {
   public:
      void sing(Song song);
};

int main() {
    Person person;
    Song song;

    person.sing(song);
}

现在,当您将实现添加到.cpp文件中时。 每个实现将单独编译(歌曲,人)。

Song.cpp

#include "song.h" // get the definition of Song

 std::string Song::getLyrics() {
    return "Every little thing, gonna be alright (bob Marley)\n";
}

Person.cpp

#include "person.h" // get the definition of Person

// Implementation
void Person::sing(Song song) {
    std::cout << song.getLyrics();
}

下一步是链接器,它在已编译文件之间链接。

即main.o,person.o和song.o之间的链接,以便main可以创建可以唱歌的人

答案 2 :(得分:1)

我曾经从一个答案中看到一个解释清楚的ascii图,但是现在找不到。

我发现了一些相似的图像。

enter image description here


enter image description here

基本上,您需要了解3个阶段:预处理阶段,编译阶段和链接阶段。我之前读过上面提供的答案,对于初学者来说,详细信息并没有太大用处。