CおよびC++で「const static」とはどういう意味ですか?

多くの人が基本的な答えを出しましたが、C++ const では誰もそれを指摘しませんでした デフォルトは static です namespace に レベル (一部は誤った情報を提供)。 C++98 標準セクション 3.5.3 を参照してください。

最初の背景:

翻訳単位: プリプロセッサが (再帰的に) すべてのインクルード ファイルをインクルードした後のソース ファイル。

静的リンケージ: 記号は、その翻訳単位内でのみ使用できます。

外部リンク: 記号は他の翻訳単位から利用できます。

namespace で レベル

これにはグローバル名前空間、別名グローバル変数が含まれます .

static const int sci = 0; // sci is explicitly static
const int ci = 1;         // ci is implicitly static
extern const int eci = 2; // eci is explicitly extern
extern int ei = 3;        // ei is explicitly extern
int i = 4;                // i is implicitly extern
static int si = 5;        // si is explicitly static

機能レベル

static 関数呼び出し間で値が維持されることを意味します。
関数 static のセマンティクス 変数は、プログラムのデータ セグメント (スタックやヒープではなく) に存在するという点でグローバル変数に似ています。static の詳細については、この質問を参照してください。 変数の寿命。

class で レベル

static クラスのすべてのインスタンスと const の間で値が共有されることを意味します 変化しないことを意味します。


C と C++ の両方で使用されます。

ご想像のとおり、static part は、そのスコープをそのコンパイル単位に限定します。また、静的初期化も提供します。 const 誰にも変更させないようにコンパイラに指示するだけです。この変数は、アーキテクチャに応じて data または bss セグメントに配置され、読み取り専用とマークされたメモリにある場合があります。

C がこれらの変数を処理する方法 (または C++ が名前空間変数を処理する方法) はこれだけです。 C++ では、static とマークされたメンバー 特定のクラスのすべてのインスタンスで共有されます。プライベートかどうかは、1 つの変数が複数のインスタンスで共有されるという事実には影響しません。 const を持つ コードがそれを変更しようとすると警告が表示されます。

厳密に非公開の場合、クラスの各インスタンスは独自のバージョンを取得します (オプティマイザーにもかかわらず)。


このコード行は、実際にはいくつかの異なるコンテキストで表示される可能性があり、動作はほぼ同じですが、わずかな違いがあります。

名前空間のスコープ

// foo.h
static const int i = 0;

'i ' ヘッダーを含むすべての翻訳単位で表示されます。ただし、実際にオブジェクトのアドレスを使用しない限り (たとえば、.'&i ')、コンパイラが 'i ' 単純にタイプ セーフ 0 として .さらに 2 つの翻訳単位が '&i を取る場所 ' その場合、アドレスは翻訳単位ごとに異なります。

// foo.cc
static const int i = 0;

'i ' は内部リンケージを持つため、この翻訳単位の外から参照することはできません。ただし、そのアドレスを使用しない限り、タイプセーフな 0 として扱われる可能性が高くなります。 .

指摘する価値のあることの 1 つは、次の宣言です:

const int i1 = 0;

正確にです static const int i = 0 と同じ . const で宣言された名前空間の変数 extern で明示的に宣言されていない 暗黙的に静的です。これについて考えてみると、const を許可するのは C++ 委員会の意図でした。 static を常に必要とせずにヘッダー ファイルで変数を宣言する ODR を破らないようにするためのキーワード。

クラスのスコープ

class A {
public:
  static const int i = 0;
};

上記の例では、標準で「i」と明示的に指定されています。 ' アドレスが不要な場合は、定義する必要はありません。つまり、'i のみを使用する場合 ' をタイプ セーフな 0 として指定すると、コンパイラはそれを定義しません。クラス バージョンと名前空間バージョンの違いの 1 つは、'i のアドレスが ' (2 つ以上の翻訳単位で使用されている場合) は、クラス メンバーに対して同じになります。アドレスを使用する場合は、その定義が必要です:

// a.h
class A {
public:
  static const int i = 0;
};

// a.cc
#include "a.h"
const int A::i;            // Definition so that we can take the address