代码对象和可执行文件之间的区别

时间:2014-09-17 16:53:32

标签: c++ linker

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

  

C ++是一种编译语言,因此您需要翻译源代码   计算机可以执行的文件。该文件由。生成   编译器和被称为对象代码(.obj),但程序就像   "你好世界"程序由我们编写的部分和部分组成   的C ++库。链接器链接程序的这两部分   生成一个可执行文件(.exe)。

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

4 个答案:

答案 0 :(得分:35)

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

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

答案 1 :(得分:10)

C ++规范是英文的技术文档。对于C++11,请查看n3337(或花费大量资金购买平装ISO标准)。从理论上讲,你不需要一台计算机来运行一个C ++程序(你可以使用一堆人类奴隶,但那是不道德的,低效的,不可靠的。)

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

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

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

  • 在编译期间启用所有警告和调试信息(例如,使用ld ....)
  • 改进您的源代码,直到您没有警告
  • 了解如何使用调试器(g++ -Wall -g
  • 能够在命令行上构建程序
  • 使用linker
  • 等版本控制系统
  • 使用好的编辑器,例如gdbemacsgeditgeany
  • 一旦您在多个源文件中编写程序,请了解如何使用gvim
  • 之类的构建器
  • 学习C ++ 11(甚至可能是git)而不是旧的C ++标准
  • 还学习其他编程语言(Ocaml,Scheme,Haskell,Prolog,Scala,....),因为它们可以提高你的思维和你在C ++中的编码方式
  • 研究用C ++编码的几个免费软件的源代码
  • 阅读您正在使用的每个功能的文档,例如在C++14cppreference(对于Linux)
  • 了解什么是man pages(你的程序有时工作的事实并没有使它正确)。

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

有时候生成某些C ++代码是有意义的,例如通过一些shell,Python或git脚本(甚至是用C ++编写的自己的程序生成C ++代码!)。

另外,要了解undefined behavior 不是编译器(但为您运行编译器)。

答案 2 :(得分:4)

多年来,用于编程计算机的语言以及各种软件开发工具已经发生了变化。

第一台计算机使用控制台上的开关输入的数字编程。

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

然后人们创建的编程语言看起来更像人们的书面语言而不是汇编程序(例如FORTRAN和COBOL和ALGOL)。这些语言更易于阅读,并且可以将单行源转换为多个机器指令,因此以这些语言而不是汇编程序编写计算机程序会更高效。

C编程语言是后来的改进,它使用了早期编程语言(如FORTRAN)的经验教训。 C使用了已经存在的一些相同的软件开发工具,例如已经存在的链接器。后来C ++被发明,开始是​​对C引入面向对象设施的改进。事实上,第一个C ++编译器实际上是一个C ++转换器,它将C ++源代码翻译成C源代码,然后用C编译器编译。然而,现代C ++直接编译为机器代码,以便使用C ++ 11及更高版本的模板,lambdas和所有其他东西提供C ++标准的全部功能。

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

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

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

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

然后人们发明了共享库和动态链接库,这就要求加载器更加复杂。加载器不仅必须将可执行文件加载到内存中才能开始运行,加载器还必须找到所需的任何共享库或动态链接库并加载它们。并且加载器还必须对附加组件(共享库)进行一定量的链接,因此加载器比以前做的要多得多。

答案 3 :(得分:2)

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

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