将源代码从Visual C++移植到GCC有哪些陷阱
What are pitfalls of porting source code from Visual C++ to GCC
众所周知,GCC比Visual C++更严格地实现C++标准。坦率地说,Visual C++只是没有很好地遵循C++标准。
对于那些主要使用Visual C++进行开发,但至少需要使用GCC来移植和编译代码的开发人员来说,这一直是一个令人头疼的问题。
MSDN非标准行为主题中记录了一些Visual C++语言的错误行为,实际上还有很多其他未记录的案例。
这篇文章的想法是记录VC++与GCC(最流行的C++编译器)的所有已知兼容性问题。当某些代码片段使用Visual C++编译而没有警告(W4级别),而不使用GCC编译(产生错误或警告)时,就会引发问题。
请注意,这只是针对标准C++问题,Microsoft特定的语言扩展(如__super
或__forceinline
)超出了范围。
建议的问题描述格式:
- 代码段(使用Visual C++编译正常)
- GCC错误或产生警告
- 两个编译器的版本都可以复制
- 对违反的C++标准语句的引用(可选,稍后可以添加)
- 解决方案(如何更改VC++和GCC都能成功编译的代码)
这是一个相当宽泛的问题,但我遇到了一些问题:
申报错误点:
#include <iostream>
struct S {
S(int) { std::cout << "Incorrectn"; }
S(S const &) { std::cout << "Correctn"; }
};
int s;
int main() {
S s(s);
}
输出应为"正确",但Visual Studio(所有版本)的输出为"不正确"。
复制分配和复制初始化的错误生成:
#include <iostream>
struct B {
B &operator = (B &) { std::cout << "Correctn"; return *this; }
template<typename T>
B &operator = (T &) { std::cout << "Incorrectn"; return *this; }
};
struct D : B {};
int main() {
D d;
d = d;
}
我想这是在Visual Studio 2012中修复的。2012年之前VS的输出为"不正确"。
两相名称查找:
#include <iostream>
static void foo(long) {
std::cout << "Correctn";
}
template<typename T>
void bar(T t) {
foo(t);
}
static void foo(int) {
std::cout << "Incorrectn";
}
int main() {
bar(1);
}
输出应该是"正确",但Visual Studio(迄今为止的所有版本)的输出都是"不正确"。
替代代币不起作用:
int main() <% %>
此程序应该编译并运行,但没有Visual Studio版本成功编译它。
循环初始值设定项子句中的用户定义类型定义:
int main() {
for (struct {int a;} a = {0}; a.a < 10; ++(a.a)) {
}
}
这是合法的,但VS不允许。
所有这些都可以在gcc和clang下正确编译和运行,可以追溯到相当多的版本。Gcc过去在两阶段查找方面有问题,但现在已经不是一段时间了。
代码片段,使用VC++2013编译正常:
struct X
{
template <class T> struct Z {};
template <> struct Z<int> {}; // Source of problem
};
产生的GCC错误(4.7.2):error: explicit specialization in non-namespace scope
违反标准条款:14.7.3 Explicit specialization, p.2 - An explicit specialization shall be declared in a namespace enclosing the specialized template.
解决方案:使用部分专业化而不是显式专业化:
struct X
{
template <class T, class MakeItPartial=void> struct Z {};
template <class MakeItPartial> struct Z<int, MakeItPartial> {};
};
或者,如果可能的话,只需将其移动到封闭的命名空间范围:
struct X
{
template <class T> struct Z {};
};
template <> struct X::Z<int> {};
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- 奇怪的结构&GCC&clang(void*返回类型)
- GCC本机矩阵运算库
- PowerPC ppc64le上的Gcc Woverloaded虚拟错误
- gcc和c++17的过载解析失败
- 数据成员SFINAE的C++17测试:gcc vs clang
- GCC对可能有效的代码抛出init list生存期警告
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 使用 GCC 卸载的 OpenMP 卸载失败,并出现"Ptx assembly aborted due to errors"
- 为什么与常规GCC不同,即使有"学究性错误",MinGW-GCC也能容忍丢失的返回类型
- 使用gcc从静态链接的文件中查找可选符号
- 普通环路未使用gcc 4.8.5自动矢量化
- 有了gcc,是否可以链接库,但前提是它存在
- 在clang++预处理器中确定gcc工具链版本
- 为什么 gcc 编译这个而 msvc 没有
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- 我可以检测和更改 gcc/g++ 中结构的当前数据对齐设置吗?
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 如何使用Clang/GCC在Mac上为C/C++设置VSCode
- 将源代码从Visual C++移植到GCC有哪些陷阱