在 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 的最佳代码的主要内容,如果未能解决你的问题,请参考以下文章