web-dev-qa-db-ja.com

.hファイルで静的グローバル変数を宣言しても大丈夫ですか?

staticキーワードは、グローバル変数のスコープをその変換単位に制限します。 .hファイルでstatic int xを使用し、その.hファイルを1つおきのファイルにインクルードすると、それらはすべて同じ翻訳単位に属しませんか?では、xはどこにでも表示されませんか?では、静的の役割は今何ですか?

また、static const int xの使用法はありますか?xはグローバル変数ですか?すべてのconstグローバル変数はデフォルトで静的ではありませんか?また、const変数のスコープは、ファイル内のforループに限定されている場合でも、TUに制限されていますか?

13
batman

あなたが書くなら

static const int x

。hファイルでは、#include-s this 。hであるすべての変換ユニットは、独自のプライベート変数xを持ちます。 。

1つのグローバル変数をすべての人に表示したい場合は、次のように記述します。

extern const int x;

。hファイルと

const int x = ...;

。cppファイルの1つ。

静的constintを1つの変換単位だけに表示したい場合は、。hファイルで言及しないでください。

36

.hファイルでstaticint xを使用し、その.hファイルを1つおきのファイルにインクルードすると、それらはすべて同じ変換単位に属しませんか?

何かを静的として宣言した場合(クラス内ではなく、クラスの静的キーワードのセマンティクスが異なるため)、その静的変数はTUの外部では表示されません。したがって、ヘッダーファイルに配置すると、そのヘッダーを含む各TUは、その静的変数の異なるプライベートコピーを持つことになります。

また、const変数のスコープは、ファイル内のforループに限定されている場合でも、TUに制限されていますか?

番号。静的const値の場合でも、スコープはその宣言によって決定されます。したがって、スコープはブラケットの場合によって制限されます。

6
Heisenbug

翻訳ごとにその変数のプライベートコピーが作成されることになり、そこに配置すると肥大化することになります。また、いたるところにランダムにコピーする必要があることも意味がありません。いいえ、それは大丈夫ではありません。

namespaceブロックでconst intを宣言できます。それで大丈夫です。

3
justin

const修飾された変数の観察可能な違いは、staticバージョンでは、変換単位ごとに1つのコピーを取得するため、そのような2つのコピーのアドレス比較が失敗する可能性があることです。

const変数のアドレスを使用しない場合、最新のコンパイラーは値を使用して変数自体を最適化できるはずです。このような場合、staticconst修飾変数は完全に問題ありません。

1
Jens Gustedt

基本的に、各ソースファイルとインクルードされたすべてのヘッダーファイルは単一の変換ユニットです。したがって、ヘッダーファイルに静的変数がある場合、ヘッダーファイルが含まれている各ソースファイル(翻訳単位)で一意になります。

「静的グローバル」は意味がありません、それらはある意味で互いに反対です。

「グローバル」という用語は、ファイルスコープの関数の外部で宣言された変数を表すために誤用されることがよくあります。むしろ、グローバル変数は外部リンケージの変数であり、プロジェクト内の任意のファイルからアクセスできます-したがってグローバルです。

外部リンケージの反対は内部リンケージです。これは、変数が宣言されている変換ユニットによってのみ変数にアクセスできることを意味します。 1つを意味する翻訳単位.cファイルとそれに含まれるすべてのヘッダー(再帰的に)。

staticは、変数が内部リンケージを取得することを保証します。したがって、他の翻訳はそれにアクセスしたり、それを参照するextern変数を宣言したりすることはできません。

ヘッダーファイルでstatic変数を宣言すると、複数の変換ユニットがその名前の個別の変数を取得します。コードは正常にコンパイルされますが、巧妙なリンカーはこれに気づき、リンカーエラーを出します。これらの種類のリンカーエラーは、多くの場合、説明的ではなく、追跡するのが困難です。

これにより、次のベストプラクティスが導き出されます。

  • ヘッダーファイル内でany変数を宣言しないでください。これにより、微妙なバグやリンカーエラーが発生することがよくあります。
  • このようなバグを防ぐために、常にすべてのヘッダーファイルを「ヘッダーガード」で囲んでください。

    #ifndef MYHEADER_H 
    #define MYHEADER_H 
      /* contents of header */ 
    #endif
    
  • ファイルスコープで宣言されたすべての変数は、プライベートカプセル化の目的で、名前空間の乱雑さを減らすために、staticで宣言する必要があります。同様に、externは、悪いデザインやスパゲッティプログラミングにつながるため、避ける必要があります。

0
Lundin