将源代码从Visual C++移植到GCC有哪些陷阱

What are pitfalls of porting source code from Visual C++ to GCC

本文关键字:GCC 陷阱 源代码 Visual C++      更新时间:2023-10-16

众所周知,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> {};