在 VS2008 和 GCC 中编译 static const int = X 的最佳代码

Posted

技术标签:

【中文标题】在 VS2008 和 GCC 中编译 static const int = X 的最佳代码【英文标题】:Best code for compiling static const int = X in VS2008 and GCC 【发布时间】:2011-08-31 21:08:15 【问题描述】:

我在编写需要在 Visual Studio 2008 和 GCC 4.6 中编译(并且还需要编译回 GCC 3.4)的 C++ 代码时遇到问题:static const int 类成员。

Other questions have covered 静态 const int 类成员所需的规则。特别是,标准和 GCC 要求变量在一个且只有一个目标文件中定义。

但是,Visual Studio 在编译包含 .cpp 文件中的定义的代码(在调试模式下)时会产生 LNK2005 错误。

我试图在其中做出决定的一些方法是:

用 .cpp 文件中的值初始化它,而不是头文件。 使用预处理器删除 MSVC 的定义。 用枚举替换它。 用宏替换它。

最后两个选项不吸引人,我可能不会使用任何一个。第一个选项很简单——但我喜欢在标题中有值。

我在答案中寻找的是一种好看的最佳实践方法来构建代码以同时让 GCC 和 MSVC 满意。我希望有一些我还没有想到的美妙的东西。

【问题讨论】:

Visual Studio 不应该那样做,我想你可能做错了。 您在使用/Za(禁用语言扩展)。如果没有,是否可以使用此开关? connect.microsoft.com/VisualStudio/feedback/details/379496/… @Branko:因为它将课堂上的所有重要内容都放在了一个地方。标题就像一个类的轮廓,值对于理解类的使用方式以及哪些值适合数组大小等很重要。 您对枚举有什么保留? @Tobias:我不确定我为什么不喜欢枚举。这似乎是在滥用他们的目的。 【参考方案1】:

我通常更喜欢 enum 方式,因为这样可以保证它始终被用作即时值并且不会获得任何存储空间。它被编译器识别为常量表达式。

class Whatever 
    enum  // ANONYMOUS!!!
        value = 42;
    ;
    ...

如果你不能那样做,#ifdef 去掉 .cpp 中的定义 用于 MSVC,因为如果你 ifdef 去掉声明中的值,它总是会得到存储;编译器不知道这个值,所以它不能内联它(好吧,如果启用,“链接时间代码生成”应该能够修复它)并且不能在需要常量的地方使用它,比如值模板参数或数组大小。

【讨论】:

在尝试了一些事情之后,我将 #ifdef 去掉 MSVC 的定义。【参考方案2】:

如果您不喜欢使用非标准黑客的想法,对于 VC++,总是有__declspec(selectany)。我的理解是,它将确保在链接时,通过删除除一个定义之外的所有冲突来解决任何冲突。您可以将其放入 #ifdef _MSC_VER 块中。

【讨论】:

好吧,__declspec 完全是一个非标准的 hack(是的,gcc 也有等效的语法,__attribute__((common)))。 @Jan Hudec - 关于common 属性的好提示。 +1。【参考方案3】:

Visual C++ 2010 接受这一点:

// test.hpp:
struct test 
    static const int value;
;

// test.cpp:
#include "test.hpp"
const int test::value = 10;

【讨论】:

引用 Zan “第一个选项很简单——但我喜欢在标题中包含值。” 是的。如果几天后没有更好的答案出现,我会接受这个。遗憾的是,这似乎是最好的选择。 @Lynx:IMO 这是最糟糕的选择,因为它强制将值存储在二进制图像中并且不允许内联它。 @Jan:您的第一部分是正确的,但第二部分不是,它仍然在 MSVC 下内联(这是由于 LTO)。 GCC 的 LTO 应该能够做到这一点(并通过 -fno-keep-static-consts 去除放置在数据部分中的未使用变量) @Necrolis:是的,LTO 应该能够解决问题。但是它依赖于优化,这可能不是由于各种微妙的原因而发生的,而向编译器提供常量在这里会给您带来其他好处(然后是 constexpr,因此可以在需要的地方使用它)。【参考方案4】:

这仍然是 VS2013 的问题。我通过将符合标准的定义放在 cpp 文件中的 #if 防止 VS 中来解决它。

啊哈:

class A

public:
  static unsigned const a = 10;
;

a.cpp:

#ifndef _MSC_VER
unsigned const A::a;
#endif

我也很好地评论了它,所以文件中的下一个人知道应该责备哪个编译器。

【讨论】:

以上是关于在 VS2008 和 GCC 中编译 static const int = X 的最佳代码的主要内容,如果未能解决你的问题,请参考以下文章

VS2008 编译时出现的错误:无法打开编译器中间文件。如何解决?

VS增量编译

VS增量编译

请教VS2012编译器二次开发CAD的问题

cmake:VS2015和GCC编译cJSON

序列化二进制结构 gcc vs cl