【问题标题】:Difference between code object and executable file代码对象和可执行文件的区别
【发布时间】:2014-11-11 19:44:24
【问题描述】:

我是 C++ 初学者,正在学习该语言的基础知识。我的书中有一个关于编译器的主题,我的问题是我无法理解文本想要说的内容:

C++ 是一种编译语言,因此您需要将源代码翻译成 计算机可以执行的文件。该文件由 编译器并被称为目标代码( .obj ),但是像这样的程序 “hello world”程序由我们编写的一部分和一部分组成 的 C++ 库。链接器链接程序的这两个部分,并 生成一个可执行文件( .exe )。

为什么我的书说计算机执行的文件是带有obj后缀的文件(目标代码),然后说是带有exe的文件 后缀?

【问题讨论】:

  • 程序的源文件被编译成目标文件,然后链接器将这些目标文件链接在一起,生成一个可执行文件。
  • 按照您的书的类比,printf("Hello, world!\n"); 是“我们编写”的部分,因此目标代码可能具有调用 printf 的指令。标准库是实际实现printf 的部分(它将如何打印??)。这就是区别。当然,通常在 C++ 中,我们将cout << "Hello, world!\n"; 作为第一个程序编写,但想法是一样的。
  • @0x499602D2 与你的对比解释这些事情一定不会太神秘。

标签: c++ linker


【解决方案1】:

目标文件是编译成二进制机器语言的源文件,但它们包含未解析的外部引用(例如printf)。它们可能需要与其他目标文件、第三方库链接,并且几乎总是与 C/C++ 运行时库链接。

在 Unix 中,object 和 exe 文件都是相同的 COFF 格式。唯一的区别是目标文件有未解析的外部引用,而 a.out 文件没有。

【讨论】:

  • 不,COFF 在大多数 Unix 中已过时。他们使用(作为 Linux)ELF!
  • 真的,谢谢。不同的缩写,相同的问题上下文不同!
【解决方案2】:

C++ 规范是英文的技术文档。对于C++11 看看里面n3337 (或者花很多钱买平装本ISO 标准)。理论上你不需要一台计算机来运行一个 C++ 程序(你可以使用一堆人类奴隶,但这会是不道德的、低效的和不可靠的)。

您可以有一个 C++ 实现,它是 interpreter,而不是 compiler(例如 Ch by SoftIntegration

如果您在笔记本电脑上安装 Linux(我建议每个学生都这样做),那么您可以拥有多个 free software C++ 编译器,尤其是 GCCClang/LLVM(分别使用 g++clang 命令)。源文件后缀为.cc,或.cxx,或.cpp,甚至.C(我更喜欢.cc),您可以要求编译器将其他后缀的文件作为C++源文件处理(但这不是传统的)。然后,object files(后缀为.o)和executables 共享相同的ELF 格式。按照惯例,可执行文件没有任何后缀(例如,g++ 是二进制可执行文件,除了启动其他进程,例如 cc1plus - 正确的编译器 -、as -assembler-、ld - linker- 等等...)

在所有情况下,我都强烈建议:

  • 在编译期间启用所有警告和调试信息(例如使用g++ -Wall -g ....)
  • 改进您的源代码,直到您没有收到任何警告
  • 了解如何使用调试器 (gdb)
  • 能够在命令行上构建程序
  • 使用像git这样的版本控制系统
  • 使用像emacsgeditgeanygvim这样的优秀编辑器
  • 一旦您在多个源文件中编写程序,学习如何使用像make 这样的构建器
  • 学习 C++11(甚至可能是 C++14)而不是旧的 C++ 标准
  • 还可以学习其他编程语言(Ocaml、Scheme、Haskell、Prolog、Scala ......),因为它们会改善您的思维方式和 C++ 编码方式
  • 学习几个用C++编写的免费软件的源代码
  • 阅读您正在使用的每个函数的文档,例如在 cppreferenceman pages(适用于 Linux)上
  • 了解什么是undefined behavior(您的程序有时可以正常工作并不能说明它是正确的)。

具体来说,在 Linux 上,您可以使用 geditemacs(使用类似 gedit hello.cc 的命令)等编辑您的 Hello World 程序(文件 hello.cc)...,使用 g++ -Wall -g hello.cc -o hello 命令编译它,使用gdb ./hello 调试它,然后重复(不要忘记使用git 命令进行版本控制)。

有时生成一些 C++ 代码是有意义的,例如通过一些 shell、Python 或 awk 脚本(或者甚至通过您自己的 C++ 代码生成 C++ 代码的程序!)。

另外,请了解IDE 不是编译器(但会为您运行编译器)。

【讨论】:

  • Clang 特别擅长报告警告和错误,而且绝对比 GCC 更擅长。它还可以更快地支持更新的标准。我推荐 OP 使用它,因为它会减少障碍。
  • 不完全正确:最近的 GCC 4.9 在警告方面有了很大改进并支持 C++11
  • 虽然 GCC 有所改进,但它的诊断仍然不够清晰,而且它也不支持 C++14(而 Clang,从 3.5 开始支持)。然而,生成的(机器)代码质量是另一回事:)。
【解决方案3】:

从 C 或 C++ 源文件创建应用程序的基本步骤如下: (1) 源文件被创建(由人或程序生成),(2) 源文件被编译(实际上是两个步骤,预处理器和编译)成目标代码,(3) 目标文件是由 C/C++ 编译器创建的链接来创建 .exe

因此,您拥有将计算机程序的一个版本(源文件)转换为另一个版本(可执行文件)的这些步骤。编译 C++ 源代码以生成目标文件。然后链接目标文件以生成可执行文件。

在大多数情况下,C 和 C++ 的编译和链接过程涉及多个不同的程序。每个程序都接收某些文件并创建新文件。

  • C/C++ Preprocessor 获取源代码文件并生成源代码文件
  • C/C++ 编译器接收源代码文件并生成目标代码文件
  • 链接器接收目标代码文件和库并生成可执行文件

What is the difference between - 1) Preprocessor,linker, 2)Header file,library? Is my understanding correct?

大多数编译器安装都有一个程序为您运行这些不同的应用程序。因此,如果您使用的是gcc,那么gcc 程序将首先运行 C++ 预处理器,然后是 C++ 编译器,然后是链接器。但是,您可以修改 gcc 使用命令行选项所做的操作,以告诉它仅运行 C++ 预处理器或仅编译源文件但不链接它们或仅链接目标代码文件。

计算机语言和编程简史

多年来,用于计算机编程的语言以及各种软件开发工具不断发展。

第一台计算机通过控制台上的开关输入的数字进行编程。

然后人们开始开发可用于更轻松、更快速地创建软件的语言和软件。第一个主要发展是创建汇编语言,其中每一行源代码都由计算机程序转换为机器代码指令。随之而来的是链接器的开发(将机器代码片段链接成更大的片段)。通过添加宏或预处理器工具来改进汇编器,这有点像 C/C++ 预处理器,虽然是为汇编语言设计的。

然后人们创建的编程语言看起来更像是人们编写的语言而不是汇编语言(例如 FORTRAN 和 COBOL 和 ALGOL)。这些语言更容易阅读,单行源代码可能会被转换成多个机器指令,因此用这些语言而不是汇编语言编写计算机程序更有效率。

C 编程语言是后来利用从早期编程语言(如 FORTRAN)中吸取的经验进行的改进。 C 使用了一些已经存在的相同软件开发工具,例如已经存在的链接器。再后来,C++ 被发明出来,开始是对 C 的改进,引入了面向对象的工具。事实上,第一个 C++ 编译器实际上是一个 C++ 翻译器,它将 C++ 源代码翻译成 C 源代码,然后用 C 编译器编译。然而,现代 C++ 直接编译为机器代码,以便通过模板、lambda 以及 C++11 及更高版本的所有其他内容提供 C++ 标准的全部功能。

链接器和加载器

当你运行一个程序时,你运行的是可执行文件。可执行文件包含多种信息。第一个是机器指令,它是编译 C++ 源代码的结果。另一个是加载器用来知道如何将可执行文件加载到内存中的信息。

在过去,很久很久以前,所有的库和目标文件都被链接到一个可执行文件中,并且可执行文件由加载器加载,加载器非常简单。

后来人们发明了共享库和动态链接库,这就要求链接器更复杂,加载器更复杂。

链接器变得更加复杂,因为它必须能够识别使用共享库和静态库之间的区别,并能够生成一个可执行文件,该文件不仅包含链接的目标代码,还包含有关加载程序的信息任何动态库。

加载器变得更加复杂,因为加载器不仅必须将可执行文件加载到内存中以便它可以开始运行,加载器还必须找到任何也需要的共享库或动态链接库并加载它们。并且加载器还必须对附加组件(共享库)进行一定量的链接,因此加载器所做的工作比过去要多得多。

另见

【讨论】:

  • 这是一个很好的答案,我还要推荐 John R. Levine 的《Linkers and Loaders》一书。
【解决方案4】:

目标代码(在目标文件中):来自编译器的输出,旨在作为链接器的输入(用于链接器生成可执行代码)。

可执行文件:准备在计算机上运行(执行)的程序

【讨论】:

    猜你喜欢
    • 2021-12-02
    • 2011-01-19
    • 2023-03-20
    • 2019-04-12
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多