将 C++ 代码从 GCC 移植到 MSVC 的良好做法?
Good practice on porting C++ code from GCC to MSVC?
我是一名学生,目前正在上编译器构建课程。我使用 GCC 和 CMake 在 Ubuntu 上用 C++ 开发我的编译器。虽然在我的开发机器上一切正常,但在学校测试中针对 MSVC 或 Visual Studio 2017 编译时,代码严重崩溃。当我追踪 MSVC 抛出的错误消息时,我注意到有几个问题导致了这些失败:
- GCC headers 提供的东西比 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是什么不是:
- 如何解决将代码从 GCC 移植到 MSVC 时的某些问题。
- 如何编写 standard-compliant 通用编译的 C++ 代码。
事实上,这个 post 要求采取实际行动将代码从 GCC 移植到 MSVC 或更好的代码,从一开始就编写没有可移植性问题的代码。 post中的例子只是为了具体讨论或说明实际难点,并不全面。我不认为关于这个问题有一个单一的真理,但我想尝试一些好的。
针对多个编译器进行编译
谈到可移植性时,有两种方法。一个迷人的、理想主义的但不切实际的:你希望编写绝对可移植的代码:即在任何编译器上按预期工作,无论是真实的还是想象的,现在的还是未来的。您可能会想说:嘿,这只是标准的 C++ 代码。不幸的是,编译器是软件,并且与任何复杂的软件一样,它们也有错误。此外,该标准有 错误 (其中追溯应用缺陷报告)。越是写复杂的代码,就越会遇到这些bug。
另一种方法是实用的。您的目标不是针对 100% 的可移植代码,而是针对一组体系结构上的一组编译器版本的可移植性。例如,您可以让您的代码在 x64 linux 和 windows、gcc
、clang
和 msvc
、最新版本或从版本 x 向上和忽略其他一切。 (该死的icc)。要实现这一点,实际上只有一种方法:在所有这些平台上测试您的代码。为此,您至少需要为代码创建单元测试,然后在所有架构和编译器上编译和 运行 这些测试。您可以手动或自动执行此过程(例如 CI)。
运行 你的代码在多个编译器上你会发现你需要修改代码以更符合标准,或者为不同的编译器和版本编写不同的代码来解决错误或限制。 SO 充满了不适用于某些主要编译器(版本)或其他编译器的兼容代码。
使用适当的开关编译
编译器有自定义扩展(一些默认启用)。你应该禁用它们。它是特定于编译器的。例如,对于 gcc
和 clang
,您需要 -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>
。
当您遇到在不同编译器上运行不同的代码时,您绝对应该调查并了解哪些是符合标准的。
我是一名学生,目前正在上编译器构建课程。我使用 GCC 和 CMake 在 Ubuntu 上用 C++ 开发我的编译器。虽然在我的开发机器上一切正常,但在学校测试中针对 MSVC 或 Visual Studio 2017 编译时,代码严重崩溃。当我追踪 MSVC 抛出的错误消息时,我注意到有几个问题导致了这些失败:
- GCC headers 提供的东西比 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是什么不是:
- 如何解决将代码从 GCC 移植到 MSVC 时的某些问题。
- 如何编写 standard-compliant 通用编译的 C++ 代码。
事实上,这个 post 要求采取实际行动将代码从 GCC 移植到 MSVC 或更好的代码,从一开始就编写没有可移植性问题的代码。 post中的例子只是为了具体讨论或说明实际难点,并不全面。我不认为关于这个问题有一个单一的真理,但我想尝试一些好的。
针对多个编译器进行编译
谈到可移植性时,有两种方法。一个迷人的、理想主义的但不切实际的:你希望编写绝对可移植的代码:即在任何编译器上按预期工作,无论是真实的还是想象的,现在的还是未来的。您可能会想说:嘿,这只是标准的 C++ 代码。不幸的是,编译器是软件,并且与任何复杂的软件一样,它们也有错误。此外,该标准有 错误 (其中追溯应用缺陷报告)。越是写复杂的代码,就越会遇到这些bug。
另一种方法是实用的。您的目标不是针对 100% 的可移植代码,而是针对一组体系结构上的一组编译器版本的可移植性。例如,您可以让您的代码在 x64 linux 和 windows、gcc
、clang
和 msvc
、最新版本或从版本 x 向上和忽略其他一切。 (该死的icc)。要实现这一点,实际上只有一种方法:在所有这些平台上测试您的代码。为此,您至少需要为代码创建单元测试,然后在所有架构和编译器上编译和 运行 这些测试。您可以手动或自动执行此过程(例如 CI)。
运行 你的代码在多个编译器上你会发现你需要修改代码以更符合标准,或者为不同的编译器和版本编写不同的代码来解决错误或限制。 SO 充满了不适用于某些主要编译器(版本)或其他编译器的兼容代码。
使用适当的开关编译
编译器有自定义扩展(一些默认启用)。你应该禁用它们。它是特定于编译器的。例如,对于 gcc
和 clang
,您需要 -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>
。
当您遇到在不同编译器上运行不同的代码时,您绝对应该调查并了解哪些是符合标准的。