c++ - Linux gcc 和 Windows Visual Studio 处理静态常量的区别?

标签 c++ visual-studio-2010 linker compiler-errors g++

我们一直在 Linux (gcc) 和 Windows (Visual Studio) 上编译一个库,正如预期的那样,发现在两个平台上获得干净编译所需的东西之间存在细微但不显着的差异。

今天,我将 gcc 编译器标志更改为使用 -fPIC(以启用共享库)。当我们测试将程序链接到库时,我们开始出现错误(第一次),undefined reference 指向 2 个在头文件中声明和初始化的静态常量(但不在 .cpp 中文件)。

我找到了 this StackOverflow answer这似乎解决了这个问题,解释说,即使 static const 在头文件中初始化,它仍然需要在代码文件中定义。进行该更改确实消除了 gcc 链接器错误。

但是,Visual Studio 不喜欢这种变化,并产生了多重定义 错误。我们必须包装需要预处理器条件的定义,以使 Visual Studio 干净地编译。

谁能告诉我这里有什么区别? (代码摘录如下。)

msg.h

class msg
{
  public:
    static const int EMPTY_INT_VALUE = INT_MAX;
    static const char EMPTY_STRING_VALUE = '\002';
    // can't define value in header, defined in cpp file
    static const double EMPTY_DOUBLE_VALUE;   
    ...
}

msg.cpp

#include "msg.h"

const double msg::EMPTY_DOUBLE_VALUE(DBL_MAX);

#ifndef _WIN32
// g++ requires these definitions, vs 2010 doesn't like them
const int msg::EMPTY_INT_VALUE;
const char msg::EMPTY_STRING_VALUE;
#endif

最佳答案

我已将其追溯到 C++ 语言规范 (INCITS/ISO/IEC 14882-2011[2012]) 的第 9.4.2 节“静态数据成员”:

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.19). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

因此,对于整数类型(例如,您的示例中的intchar),您可以初始化类定义。如果这样做,您必须还在命名空间范围内(即在您的 .cpp 文件中)定义它并且没有初始化程序。在该规范的该部分的其他地方声明,在其类中声明 static 数据成员不是定义并且必须,因此,伴随命名空间范围内的定义,这就是您在示例中所做的。

GCC 遵循规范的这一部分,而 Visual C++ 则没有。我使用 Visual Studio 2012 进行了测试。

Here's another discussion of Visual C++'s noncompliance in this regard.此处描述的解决方法正是您正在做的:保护积分变量的定义,尽管它们使用的是 _MSC_VER

关于c++ - Linux gcc 和 Windows Visual Studio 处理静态常量的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18087464/

相关文章:

c# - 无法在 VS 2010 性能分析器中捕获 CPU 指标

c++ - 在哪里可以找到 libboost_random?

iphone - 导入第三方项目时出现链接器错误

C++模板T,检测Type为字符串形式

c++ - 为什么要打印 ascii 范围之外的数字?

c++ - operator new 负数

asp.net - 我是否必须将网站项目转换为 Web 应用程序项目才能迁移到 Azure?

c++ - 线程 : Segmentation fault error

c# - I18N C# 应用程序

makefile - 如何使用 cmake 链接 jemalloc 共享库