c++应用程序是跨平台的吗?

Are C++ applications cross-platform?

本文关键字:跨平台 应用程序 c++      更新时间:2023-10-16

我在学生时代学到的第一件事就是c++应用程序不能在不同的操作系统上运行。最近,我读到基于Qt的c++应用程序可以在任何地方运行。那么,到底发生了什么?c++应用程序是否跨平台?

  1. 源代码兼容。如果我编译源代码,它会在任何地方运行吗?

  2. API/ABI兼容性。操作系统是否以代码可以理解的方式为其组件提供接口?

  3. 二进制兼容性。代码是否能够在目标主机上运行?

源代码兼容

C++是一个标准,它定义了如何读写结构,内存,文件。

#include <iostream>
int main( int argc, char ** argv )
{
     std::cout << "Hello World" << std::endl;
}

用于处理数据的代码(如grep, awk, sed)通常是跨平台的。

当你想与用户交互时,现代的操作系统有一个GUI,这些GUI不是跨平台的,并且导致代码为特定的平台编写。

qtwxWidgets这样的库有多个平台的实现,允许你为qt而不是WindowsiOS编程,结果与两者兼容。

这些匿名化的库的问题是,为了实现跨平台的一致性,它们剥夺了平台X的一些特定好处。

例如在Windows上使用WaitForMultipleObjects函数,它允许您等待不同类型的事件发生,或者在UNIX上使用fork函数,它允许您的进程的两个副本以重要的共享状态运行。在UI中,表单的外观和行为略有不同(例如颜色选择器,最大化,最小化,跟踪窗口外鼠标的能力,手势的行为)。

当您需要完成的工作对您来说很重要时,那么您可能最终想要编写特定于平台的代码来利用特定应用程序的优势。

Csqlite是广泛的跨平台代码,但它的低级IO是特定于平台的,因此它可以保证数据库的完整性(即数据确实被写入磁盘)。

所以像Qt这样的库可以工作,它们可能会产生令人不满意的结果,你最终不得不编写本机代码。

API/ABI兼容性

不同版本的UNIX和Windows彼此之间有某种形式的兼容性。这允许为一个版本的操作系统构建的二进制文件在其他版本的操作系统上运行。

在UNIX中,构建机器的选择定义了兼容性。您希望支持的最低操作系统版本应该是您的构建机器,它将生成与后续次要版本兼容的二进制文件,直到它们做出重大更改(弃用库)。

在Windows和Mac OS X上,你选择一个SDK,它允许你针对一组具有相同问题的操作系统进行破坏性更改。

在Linux上,每个内核版本都是ABI不兼容的,并且内核模块需要为每个内核版本重新编译。

二进制兼容性

这是CPU理解代码的能力。这比您想象的要复杂得多,因为x64芯片能够(取决于操作系统的支持)运行x86代码。

典型的c++程序被打包在一个容器(PE可执行,ELF格式)中,操作系统使用该容器来解压缩代码和数据部分以及加载库。这使得最终的程序同时具有二进制(代码类型)和API(容器格式)形式的不兼容性。

同样在今天,如果你编译一个x86的Windows应用程序(目标是Windows 7在Visual Studio 2015上),那么如果处理器没有SSE2指令(大约10年的CPU),代码可能无法执行。

最后,当苹果公司从PowerPC改为x86时,他们提供了一个仿真层,允许旧的PowerPC代码在x86平台的模拟器中运行。

所以总的来说二进制不兼容是一个模糊的区域。有可能产生一个识别无效指令的操作系统(例如SSE2),并在故障中模拟行为,这可以随着新功能的出现而更新,并保持您的代码运行,即使它是二进制不兼容的。

即使您的平台无法运行某种形式的指令集,也可以对其进行模拟并使其兼容。

标准c++在"一次编写,随处编译"的意义上是跨平台的,而不是在"一次编译,随处运行"的意义上。

这意味着如果你用标准c++编写程序,你可以编译并在任何具有标准c++实现的目标环境中运行它。

你可以不编译你的程序在你的机器上,发送二进制文件,然后期望它在其他目标上工作。(至少一般来说不是这样。当然,在某些条件下可以从c++代码分发二进制文件,但这取决于实际的目标。这是一个广阔的领域。


当然,如果使用额外的非标准特性,如gcc的可变长度数组或第三方库,则只能在提供这些扩展和库的系统上进行编译。

像Qt和Boost这样的库在许多系统上都是可用的(至少我相信这两个库在Linux, Mac和Windows上),所以如果你使用它们,你的代码将保持跨平台。

可以实现您的源在不同的平台上编译,从而为您提供来自同一源库的各种二进制文件。

这不是像Java或c#那样"编译一次,在合适的VM下到处运行",而是像C那样"编写一次,在合适的环境下到处编译 "。

由于标准库不提供您可能需要的一切,您必须寻找第三方库来提供该功能。某些框架——如Boost、Qt、GTK+、wxWidgets等——可以提供这种功能。由于这些框架都是以在不同平台上编译的方式编写的,因此可以实现上述意义上的跨平台功能。


如果你想让你的c++代码是跨平台的,有很多事情需要注意。

最明显的是source对数据类型做了的假设。您的long可能在这里是32位,在那里是64位。数据类型对齐和结构体填充可能有所不同。这里有一些"安全"的方法,比如size_t/size_type/uint16_t类型等等,也有一些错误的方法,比如wchar_tstd::wstring。这需要纪律和一些经验来"把它做好"。

不是所有的编译器都是一样的。如果您需要您的源代码在其他c++编译器上编译,则不能使用所有最新的c++语言特性,或者使用依赖于这些特性的库。请先检查兼容性表。

另一个是端序。仅举一个例子,当您在一个平台(例如x86或x86_64)上向文件写入整数流,然后在另一个平台(例如POWER)上再次读取它时,您可能会遇到问题。为什么要将整数写入文件?嗯,UTF-16 整数…再一次,纪律和一些经验对使这一过程变得相当轻松大有帮助。

一旦您选中了所有这些框,您需要确保您的代码所基于的库的可用性。虽然std::是安全的(但请参阅上面的"并非所有编译器都是平等的"),但如果您着眼于主流之外,boost::这样无害的东西可能会成为问题。(在过去的几年里,我帮助Boost人员修复了一两个关于AIX/Visual Age的问题,因为他们无法访问该平台来测试新版本…)

哦,还要注意各种许可方案。一些框架(如Qt或Cygwin)可以提高您的跨平台能力,但它们有附加条件。这并不是说它们在适当的情况下没有很大的帮助,只是你需要了解copyleft/专有许可要求。


说了这么多,有Wine("Wine不是仿真"),它使为Windows编译的可执行文件在各种类unix系统(Linux, OS X, *BSD, Solaris)上运行。它的能力有一定的限制,但它一直在变得更好。

是。不。也许吧。什么是跨平台c++代码?跨平台c++代码就是这样一种代码,它可以在不同的操作系统下编译而不需要修改。

这意味着,如果您显式地使用任何与平台相关的头文件,您的代码就不再是跨平台的。Qt以以下方式解决了这个问题:它们为所有特定于平台的东西提供包装器。例如,假设您正在使用QFile打开/读取/写入文件。你的代码看起来像

QFile file(filename);
file.open(QFile::ReadOnly);
//other stuff

您可以在任何操作系统下编译此代码,只要您有适合该操作系统的编译器和Qt库。隐藏在QFile下的代码将使用适合操作系统的文件处理函数,但这与您无关。

同样,如果你只使用标准库,你的代码可以在任何有c++编译器的地方编译。

但是,已经编译的应用程序不像Java应用程序那样是跨平台的——例如,你不能在Windows上编译一个应用程序,然后在Linux上运行,你必须在Linux下重新编译你的代码。

c++是跨平台的。您可以使用它来构建可以在许多不同操作系统上运行的应用程序。

不是跨平台的是将c++转换为目标代码的编译器。据我所知,没有一个编译器具有所有必要的功能,所以当你用它来编译c++程序时,它会自动运行在Windows、Linux和Mac OS上。

Qt Creator集成了多个编译器并具有构建自动化。它使在不同的设置和目标平台之间切换变得容易。它不仅为桌面环境,也为移动设备提供构建、运行和部署c++应用程序的支持。

c++是一种编程语言。文本。因此,它不会在任何地方运行。

符合标准c++代码在任何平台上的行为都是一样的;"跨平台",如果你愿意的话。编写(严格)符合c++的代码需要迂腐,因为一些假设通常依赖于实际实现的最终细节,而这些细节继承自c++本身的目标。

注意我们仍然在讨论c++代码,而不是c++程序。事实上,当我们传递到术语"程序"时,我们没有更多的保证,因为我们不再谈论c++了;而是编译器的输出。这就是可移植性开始消失的地方:可执行格式、ISA、ABI、低级例程等等。
你能相信吗?如果不能,则需要通过重新编译或使用特定于平台的元素,将c++程序集成到它将运行的环境中。