4

Linux (gcc) と Windows (Visual Studio) の両方でライブラリをコンパイルしてきましたが、予想どおり、両方のプラットフォームでクリーンなコンパイルを取得するために必要なものに、わずかではあるが大きな違いは見られませんでした。

今日、gcc コンパイラ フラグを使用するように変更しまし-fPICた (共有ライブラリを作成できるようにするため)。ライブラリに対してプログラムをリンクするテストを行ったところ、ヘッダー ファイルで宣言および初期化された 2 つの静的定数で (初めて) エラーが発生し始めました undefined reference(.cpp ファイルではありません)。

問題に対処しているように見えるこのStackOverflowの回答を見つけましstatic constた.ヘッダーファイルで初期化されていても、コードファイルで定義する必要があることを説明しています。そして、その変更を行うと、gcc リンカー エラーが削除されました。

しかし、Visual Studio はその変更を気に入らず、multiple definitionエラーを生成しました。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
4

1 に答える 1

2

C++言語仕様( INCITS/ISO/IEC 14882-2011[2012] )のセクション9.4.2「静的データメンバー」まで追跡しました:

不揮発性const staticデータ メンバーが整数型または列挙型の場合、クラス定義でのその宣言は、代入式であるすべての初期化子句が定数式 (5.19)であるブレースまたはイコール初期化子を指定できます。リテラル型のデータ メンバーは、指定子を使用してクラス定義で宣言できます。その場合、その宣言は、割り当て式であるすべての初期化子節が定数式であるブレースまたは等号初期化子を指定するものとします。[注:どちらの場合も、メンバーは定数式に現れる場合があります。—終わりのメモstaticconstexpr] プログラムで ODR 使用 (3.2) され、名前空間スコープ定義に初期化子が含まれていない場合、メンバーは名前空間スコープで定義されます。

したがって、整数型の場合 (たとえばintchar例では)、クラス定義で初期化できます。その場合、名前空間スコープ (つまり、ファイル内) で初期化子なしで定義する必要があります。仕様のそのセクションの他の場所では、クラス内のデータメンバーの宣言は定義ではないため、名前空間スコープでの定義を伴う必要があると述べられています。これは、例で行っていることです。.cppstatic

GCC は仕様のこの部分に従っていますが、Visual C++ はそうではありません。Visual Studio 2012 でテストしました。

この点に関する Visual C++ の非準拠についての別の説明を次に示します。ここで説明する回避策は、まさにあなたが行っていることです: 整数変数の定義を保護しますが、_MSC_VER.

于 2013-08-06T18:18:23.210 に答える