将 C++ 代码从 GCC 移植到 MSVC 的良好做法?

Good practice on porting C++ code from GCC to MSVC?

我是一名学生,目前正在上编译器构建课程。我使用 GCC 和 CMake 在 Ubuntu 上用 C++ 开发我的编译器。虽然在我的开发机器上一切正常,但在学校测试中针对 MSVC 或 Visual Studio 2017 编译时,代码严重崩溃。当我追踪 MSVC 抛出的错误消息时,我注意到有几个问题导致了这些失败:

为奠定讨论基础,请参阅以下示例, 它适用于 GCC 但在 MSVC 上中断。

#include <iostream>

int main() {
  std::string S;
  std::getline(std::cin, S);
}

MSVC 需要 #include <string> 才能工作。

#include <unordered_map>

int main() {
  std::min(1, 2);
}

MSVC 需要 #include <algorithm> 才能工作。

这些问题一旦爆发并不难解决:我可以 #include 所需的 headers。但是,太昂贵了,不能让它们爆发。它带走了我的分数,伤害了我。

我没兴趣讨论哪个编译器更好standard-compliant。我只是想在他们抓住我之前抓住任何可移植性问题。但我不是 well-informed 这些编译器之间所有那些棘手的差异。这就是为什么我要求提供工具来解决这些问题。我想更新我的工具链以编写更可移植的代码。

编辑:除了工具,我会虚心学习编写可移植代码的任何代码规则、良好实践和已知问题。

编辑:对不起各位。我并不是要让第二个例子出错(只是删除)。我只是无法访问 MSVC 来重现问题。

编辑澄清:这个post是什么不是

  1. 如何解决将代码从 GCC 移植到 MSVC 时的某些问题。
  2. 如何编写 standard-compliant 通用编译的 C++ 代码。

事实上,这个 post 要求采取实际行动将代码从 GCC 移植到 MSVC 或更好的代码,从一开始就编写没有可移植性问题的代码。 post中的例子只是为了具体讨论或说明实际难点,并不全面。我不认为关于这个问题有一个单一的真理,但我想尝试一些好的。

针对多个编译器进行编译

谈到可移植性时,有两种方法。一个迷人的、理想主义的但不切实际的:你希望编写绝对可移植的代码:即在任何编译器上按预期工作,无论是真实的还是想象的,现在的还是未来的。您可能会想说:嘿,这只是标准的 C++ 代码。不幸的是,编译器是软件,并且与任何复杂的软件一样,它们也有错误。此外,该标准有 错误 (其中追溯应用缺陷报告)。越是写复杂的代码,就越会遇到这些bug。

另一种方法是实用的。您的目标不是针对 100% 的可移植代码,而是针对一组体系结构上的一组编译器版本的可移植性。例如,您可以让您的代码在 x64 linux 和 windows、gccclangmsvc、最新版本或从版本 x 向上和忽略其他一切。 (该死的icc)。要实现这一点,实际上只有一种方法:在所有这些平台上测试您的代码。为此,您至少需要为代码创建单元测试,然后在所有架构和编译器上编译和 运行 这些测试。您可以手动或自动执行此过程(例如 CI)。

运行 你的代码在多个编译器上你会发现你需要修改代码以更符合标准,或者为不同的编译器和版本编写不同的代码来解决错误或限制。 SO 充满了不适用于某些主要编译器(版本)或其他编译器的兼容代码。

使用适当的开关编译

编译器有自定义扩展(一些默认启用)。你应该禁用它们。它是特定于编译器的。例如,对于 gccclang,您需要 -pedantic。我不知道 msvc。但即使是这些 are not enough:

Some users try to use -Wpedantic to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all—only those for which ISO C requires a diagnostic, and some others for which diagnostics have been

使用与编译器互补的工具

使用static analyzer 工具。这些工具分析您的代码并捕获一些错误、非法或未定义行为代码。

另请查看 clang 消毒剂。

不要忘记标准

你说你对讨论哪个更符合标准不感兴趣,但你至少应该对符合标准的代码感兴趣。例如,在您的第一个示例中,即使它恰好适用于您的 gcc 版本,该代码也是非法的,因为此处的标准要求包含 <string><algorithm>

当您遇到在不同编译器上运行不同的代码时,您绝对应该调查并了解哪些是符合标准的。