什么时候需要编译C / C ++?

时间:2013-12-23 15:46:23

标签: c++ c compiler-construction

这个问题假定编写的C / C ++代码是可移植的,不使用特定于平台的代码。

我开始学习C ++以及如何编译代码。我知道C的创建是为了避免使用汇编语言,因为必须为不同的硬件配置重写程序。我也知道必须为不同的计算机配置重新编译C / C ++。

这让我想知道新配置是什么构成的。我可以从互联网上下载一个工作正常的可执行文件,互联网显然不知道我的硬件配置。是否必须为每个不同的CPU编译代码?为一个OS版本编译的代码是否适用于另一个OS版本? (Windows 7代码是否适用于Windows 8而无需重新编译?)

简而言之,什么条件定义了必须编译的新配置?

4 个答案:

答案 0 :(得分:13)

C和C ++是编译的编程语言。 compiled language是一种编程语言,其实现通常是编译器 - 从源代码生成机器代码的转换器 - 而不是解释器。机器代码是由计算机处理器直接执行的一组指令。有两件事使程序与硬件/软件组合不兼容。您正在尝试运行二进制文件的机器(硬件)中最重要的一个。例如,您需要知道在64位CPU上编译的程序无法在32位或ARM处理器上运行。

dozens computer architectures和子架构。主要架构是x86,x86_64(amd64),可能还有ARM。如果您使用的语言将其代码编译为机器代码,则只能在具有与您的CPU兼容的计算机上分发二进制工件(除非您进行交叉编译)。

硬件不是平台之间的唯一区别。通常,您的代码应在满足CPU之前由操作系统处理。执行此工作的操作系统部分称为application Binary Interface。即使在同一台机器上,也无法运行在Linux上使用Windows编译的ELF二进制文件,因为Win32可执行文件不同。

答案 1 :(得分:10)

在硬件级别,必须为每个处理器体系结构编译C程序。为x86编译的代码可以在x86处理器上运行,无论是型号还是制造商(intel / amd),但不适用于Itanium架构。

对于操作系统,如果程序使用特定于操作系统的库,则它只能在该操作系统上运行。例如,从Windows使用CreateFile的程序仅适用于Windows。有些方法,比如宏,程序可以根据编译的操作系统调用不同的函数。即使一个程序只调用便携式(ISO)函数,它仍然需要为每个操作系统(windows,linux,mac)重新编译,因为每个操作系统的可执行格式都不同(linux使用ELF,windows使用PE)。

此外,例如,当您部署库时,对于特定的操作系统和体系结构,有时您需要有2个已编译的版本:发行版和调试版。

编译器具有针对某些体系结构的优化选项,因此您将获得可在任何x86体系结构上运行的程序,但针对Intel Nehalem处理器进行了优化。

有时,新处理器引入了透明的新硬件功能,即代码不需要重写,但是,为了使程序从中受益,必须使用新版本的编译器重新编译程序可以利用这些新功能。一个例子是Pentium Pro,它引入了新的条件移动指令(C代码不需要重写,但编译器需要知道,以便生成这些指令)。

答案 2 :(得分:5)

是什么让你认为C或C ++ 被编译?它恰好是传统方法。至少有三种不同的C ++执行方式:

  1. 传统上编译C和C ++是为了在给定系统上实现最高性能。
  2. 某些系统将代码转换为中间格式,然后由合适的虚拟机进行评估,例如,llvm执行此操作。显然它假设llvm安装在执行它的机器上。
  3. 可以解释C和C ++。例如,cling是一个C ++解释器。
  4. 编译步骤本身甚至在考虑运行程序之前验证是否满足某些约束,主要是为了捕获错误。除了捕获错误之外,能够在运行正在执行的内容之前确定具有一些性能优势。编译本机指令有几个性能优势:

    1. 代码可以对整数的大小做出明智的决定,支持浮点单元,所需的内存对齐等。
    2. 本机指令由系统的硬件评估,该硬件往往更有效
    3. 链接到库时,可以在链接时确定各种函数的入口点,可能避免函数调用开销。
    4. 虽然为程序执行的启动和终止代码在不同的操作系统之间有所不同,但操作系统本身通常并没有太大的区别。此外,可用的库和API如何访问常见操作是不同的,有时需要采用不同的方法来有效地编写应用程序。

答案 3 :(得分:2)

正如Dietmar解释的那样,C ++甚至都不需要 汇编(曾经有一个小组参与了尝试 标准化C的一些“半编译”格式,以便你可以 下载一个程序,它可以在任何Unix平台上运行)。所以 最终的答案是它必须重新编译时 实现文档说它必须重新编译。 (这称为二进制兼容性,以及大多数C ++编译器 记录什么是兼容的,什么不兼容。)

在实践中,对于大多数实现:

  • 如果更改,则必须重建(编译和链接) 体系结构或基本操作系统:通常为Linux编译的代码 不会在Windows下运行,甚至不能在Solaris和代码下运行 为Sparc编译的将无法在英特尔架构上运行。

  • 如果您想利用,通常需要重新编译 较新的功能。如果您想在较旧的平台上运行,那么 也可能必须在它们上编译,或指定某种类型 编译时编译器的兼容性选项,这样 编译后的代码(和库)不会使用任何新的代码 特征。因此,例如,默认情况下,VS的最新版本 使用旧版本中不存在的机器说明 英特尔架构(但速度要快得多) 至少涉及浮点的地方)。但他们有选择权 告诉编译器不要使用这些说明。

如果你想知道事情会有多大变化,甚至 对于相同的架构和相同的操作系统,您可以看看 在g ++的体系结构相关选项 (http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/i386-and-x86_002d64-Options.html#i386-and-x86_002d64-Options)。 并非所有选项都会影响二进制兼容性, 但他们中的很多人都这样做。 特别是-mfpmath之类的内容:如果您使用-mfpmath=387 (我认为这是g ++的默认值),你的程序将继续运行 几乎所有英特尔32位架构;如果你使用其中一个 其他选项,它可能无法在某些较旧的处理器上运行 (但它会在新的oned上运行得更快 - 并给予 结果不同,因为浮动的特点 点处理器是不同的。)