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

Difference between code object and executable file

本文关键字:区别 可执行文件 对象 代码      更新时间:2023-10-16

我是c++初学者,正在学习这门语言的基础知识。在我的书中有一个关于编译器的话题,我的问题是我不能理解文本想说什么:

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

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

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

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

c++规范是一份英文技术文档。对于c++ 11,请查看n3337内部(或者花很多钱购买平装本ISO标准)。从理论上讲,你不需要一台计算机来运行一个c++程序(你可以使用一群人类奴隶,但那将是不道德的、低效的和不可靠的)。

你可以有一个c++实现,它是一个解释器,而不是一个编译器(例如,Ch by SoftIntegration)

如果你在笔记本电脑上安装Linux(我建议每个学生都这样做),那么你可以有几个自由软件c++编译器,特别是GCC和Clang/LLVM(分别使用g++clang命令)。源文件的后缀为.cc,或.cxx,或.cpp,甚至.C(我更喜欢.cc),您可以要求编译器将其他后缀的文件作为c++源文件处理(但这不是常规的)。然后,目标文件(后缀为.o)和可执行文件共享相同的ELF格式。通常,可执行文件没有任何后缀(例如,g++是一个二进制可执行文件,除了启动其他进程,如cc1plus-编译器-,as-汇编器-,ld-链接器-等等…)

在任何情况下我都强烈建议:

  • 在编译过程中启用所有警告和调试信息(例如使用g++ -Wall -g....)
  • 改进你的源代码,直到你没有警告
  • 学习如何使用调试器(gdb)
  • 能够在命令行上构建程序
  • 使用git
  • 等版本控制系统
  • 使用emacs,gedit,geanygvim等编辑器
  • 一旦你在几个源文件中编写程序,学习如何使用make等构建器
  • 学习c++ 11(甚至可能是c++ 14)而不是旧的c++标准
  • 也可以学习其他编程语言(Ocaml, Scheme, Haskell, Prolog, Scala, ....),因为它们会改善你的思维和你在c++中的编码方式
  • 研究几个用c++编写的自由软件的源代码
  • 读取您正在使用的每个函数的文档,例如在cppreference或手册页(对于Linux)
  • 来理解什么是未定义行为(你的程序有时工作并不使它正确)。

具体来说,在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是而不是编译器(而是为您运行编译器)。

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

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

在大多数情况下,在C和c++的编译和链接过程中涉及到几个不同的程序。每个程序接收特定的文件并创建新文件。

  • C/c++预处理器接收源代码文件并生成源代码文件
  • C/c++编译器接受源代码文件并生成目标代码文件
  • 链接器接受目标代码文件和库并生成可执行文件

参见- 1)预处理器,链接器,2)头文件,库之间的区别是什么?我的理解对吗?

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

计算机语言与程序设计简史

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

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

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

然后人们创造了看起来更像人类书面语言而不是汇编语言的编程语言(例如FORTRAN、COBOL和ALGOL)。这些语言更容易阅读,一行源代码可以转换成几条机器指令,因此用这些语言编写计算机程序比用汇编语言编写程序效率更高。

C程序设计语言是从早期的程序设计语言(如FORTRAN)中学到的经验教训中提炼出来的。C语言使用了一些已经存在的软件开发工具,比如已经存在的链接器。再晚些时候,c++被发明出来,最初是作为C的改进引入了面向对象的功能。事实上,第一个c++编译器实际上是一个c++翻译器,它将c++源代码翻译成C源代码,然后用C编译器编译。然而,现代c++被直接编译成机器码,以提供c++标准的全部功能,包括模板、lambdas和c++ 11及以后版本的所有其他功能。

链接器和加载器

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

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

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

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

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

参见

  • 共享对象(.so)、静态库(.a)和DLL's (.so)之间的区别?

  • 什么是应用二进制接口(ABI)?

  • 如何制作一个简单的c++ Makefile

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

Executable:准备在计算机上运行的程序

(.obj)文件代表'object'。在学习或使用OOP(面向对象编程)时。如果没有(.obj),就没有可执行文件。就像它说的(.obj)或object "file",确保程序连接到某些东西,以便它可以被使用。因此,基本上,可执行文件将是创建一个.exe(可执行文件)的过程,以便在shell上运行,其中包含(.obj)文件的内容。