我是一名学生,目前正在上编译器构造课程。我使用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
所需的标头。但是,让它们爆发的价格太贵。它夺走了我的分数并伤害了我。
我没有兴趣讨论哪种编译器更符合标准。我只是想先解决任何可移植性问题,然后再抓住我。但是我对这些编译器之间的所有棘手差异并不了解。这就是为什么我需要工具来解决这些问题。我想更新工具链以编写更多可移植的代码。
编辑:除了工具之外,我还将谦虚地学习编写可移植代码的所有代码纪律,良好实践和已知问题。
编辑:抱歉!我并不是要使第二个示例错误(只是删除)。我只是无法访问MSVC来重现问题。
编辑以澄清问题:不是该帖子的目的:
实际上,这篇文章要求人们采取实际行动,将代码从GCC移植到MSVC或更好,以便从一开始就编写没有可移植性问题的代码。这篇文章中的示例用于使讨论更具体或显示实际困难,但并不全面。我不认为这个问题有一个单一的真理,但我想尝试一些好的问题。
答案 0 :(得分:1)
关于可移植性,有两种方法。一种迷人的,理想的,但不切实际的方法:您希望编写绝对可移植的代码:即,可以在当前和将来的任何编译器上工作,无论是实际的还是虚构的。您可能会想说:嘿,这只是标准的C ++代码。不幸的是,编译器是软件,并且像任何复杂的软件一样,它们都有错误。此外,该标准还包含 bug (缺陷报告可追溯应用)。您编写的代码越复杂,遇到这些错误的机会就越多。
另一种方法是实用的方法。并非针对100%可移植的代码,而是针对在一组体系结构上的一组编译器版本上实现可移植性。例如,您可以针对您的代码在x64 linux和Windows(最新版本gcc
clang
和msvc
或从x向上的版本)上运行而忽略其他所有内容。 (该死)。为此,实际上只有一种方法:在所有这些平台上测试代码。为此,您至少需要为代码创建单元测试,然后在所有体系结构和编译器上编译并运行这些测试。您可以手动执行此操作,也可以自动执行该过程(例如CI)。
在多个编译器上运行代码,您将发现您需要修改代码以使其更符合标准,或者为不同的编译器和版本编写不同的代码,以避开错误或限制。 SO充满了在某些主要编译器(版本)或其他编译器上不起作用的兼容代码。
编译器具有自定义扩展名(默认情况下已启用某些扩展名)。您应该禁用它们。它是特定于编译器的。例如,对于gcc
和clang
,您需要-pedantic
。我不知道msvc
。但即使是这些are not enough:
某些用户尝试使用-Wpedantic检查程序是否符合严格的ISO C 一致性。他们很快发现它并不能完全满足他们的要求: 它找到了一些非ISO的做法,但不是全部-仅针对那些ISO做法 C需要诊断,而其他一些则需要诊断
使用static analyzer工具。这些工具会分析您的代码,并发现一些错误,非法或未定义行为的代码。
也请看一下lang消毒剂。
您说您对讨论哪个更符合标准不感兴趣,但是至少应该对符合标准的代码感兴趣。例如,在您的第一个示例中,即使它碰巧适用于您的gcc
版本,该代码也是非法的,因为此处的标准要求包含<string>
和<algorithm>
。
当您遇到在不同的编译器上以不同方式工作的代码时,您绝对应该研究并查看符合标准的内容。