DOSEIの日記

技術メモ+日常ログ

グローバルスコープと内部リンケージ

C では通常、グローバルスコープに置かれた宣言や定義は他のオブジェクトから参照可能。つまり、あるソースで

int gVar;

とあれば、他のソースで

extern int gVar;

とすれば、リンカがこの2つを結合してくれる。しかし、間違って同じ名前のグローバル変数が複数あったりすると、リンクの結果がどうなるかは神のみぞ知る。

こういうことがないように、(なぜかデフォルトでは公開されてしまってるのを) static を修飾することで他の翻訳単位との結合を禁止できる。これを内部リンケージという。

しかし

によれば、 C++ ではこれは非推奨らしい。
これと同じことを実現するために、全ての(公開すべきでない)グローバル変数無名名前空間に置くべきとしている。
つまり、

namespace // 名前空間名を書かない
{
  int gVar; // "static" はいらない
} // ";" はいらない

これで、このソース内でしか結合されない。無名なので外部からリンクしようにも指定できない。

また、同じ名前空間は離散的にかかれていても(ブロックが複数あって離れていても)1つの空間とみなされ、それが複数の翻訳単位(ソース)にまたがってても適用される。じゃあ無名名前空間も?
実は、無名名前空間はそれぞれの翻訳単位で別の空間とみなされる。要するにだれも教えてはくれないけど、こっそりと秘密の名前をもってて、ソース内ならそれを意識しなくても特別な記法で使えるというわけ。その特別な記法とは、スコープ解決演算子をつけないこと、つまり変数名(とか)をそのまま書けばいい。要するに、秘密の名前が using namespace で宣言されているということ。

ちなみにスコープ解決演算子で何も書かない

::gVar

は、グローバルスコープにおける gVar を表すので、無名空間の中の gVar にはならないので注意し、暗黙の using が行われているため、無名名前空間の gVar を指すことができる。(間違ったこと書いてました。信じた人はごめんなさい。)