今回のタイトルはやや分かりにくいかもしれません。「非局所オブジェクト」というのは、関数の外で宣言したオブジェクトのことです。いわゆる「グローバル変数」とほぼ同じと考えてください。
さて、関数の外で宣言された「非局所オブジェクト」ですが、static 記憶クラス指定子が付いていれば内部結合になることはいうまでもありません。今回話題にするのは、記憶クラス指定子が付いていないデフォルトの状態での結合がどうなるかです。
結論からいうと、非局所オブジェクトが外部結合になるか内部結合になるかは、C と C++ では異なります。これは、C と C++ の間の重要な非互換性のひとつです。
まず、C の場合には、明示的に static 記憶クラス指定子を付けない限り、非局所オブジェクトは必ず外部結合になります。それに対して、C++ では、const 修飾子が付いた非局所オブジェクトは、デフォルトでは内部結合になります。
では、const 修飾子と同じ仲間である volatile 修飾子はどうかというと、これは結合の種類には影響を与えません。const volatile のように両方の修飾子が付いた場合には、やはり const 修飾子が付いているので内部結合になります。
では、C++ では、どのように書けば const 修飾子のついた非局所オブジェクトを外部結合にできるのでしょうか? それは、次のようにします。
extern const int foo = 123;
上のように、明示的に extern 記憶クラス指定子を付けることで、const 修飾子が付いていても外部結合にすることができます。C では、extern 記憶クラス指定子は(定義ではなく)宣言だけのために、主にヘッダファイルで使っていたと思いますが、C++ では、このように定義の際にも extern 記憶クラス指定子を記述する必要が出てきます。
なお、単なる外部結合ではなく、C 結合にする場合には、
extern "C" const int foo = 123;
のようにしなければなりません。
ところで、非局所オブジェクトを外部結合にする場合には、通常ヘッダファイルの中でも宣言を行うかと思います。その場合、
// foo.hpp extern const int foo; // foo.cpp const int foo = 123;
のように、定義時には extern 記憶クラス指定子を省略することも可能です。ただし、(上の例で言えば)foo.cpp から foo.hpp がインクルードされていることが絶対条件です。
これまでの例は比較的簡単でした。しかし、実際にはもっと判断しにくいケースもあります。
const char s1[] = "abc"; const char* s2 = "def";
上のコードに出てくる s1 と s2 は、それぞれ外部結合でしょうか? それとも内部結合でしょうか?
正解は、s1 は内部結合であり、s2 は外部結合です。s2 は確かに const 修飾子が付いていますが、それはあくまでも参照先の型についてであり、ポインタ型自体が const で修飾されているわけではありません。ですから、
const char* const s3 = "ghi";
のようにすれば、s3 は内部結合になります。
C または C++ しか使わなければ、この非互換性に悩まされることはあまりないでしょう。しかし、両方の言語を使い分けなければならないとき、油断していると、ついついはまってしまう落とし穴です。
トラックバック
ブックナビゲーション
- 技術情報
- Boost C++ Libraries メモ
- C++と組込み環境
- C++サンプル集
- C++テンプレート集
- C++プログラマのためのC言語入門
- C/C++迷信集
- [迷信] 'A'~'Z' の値は連続している
- [迷信] 0xe-0xe はゼロ
- [迷信] 1 バイトは 8 ビット
- [迷信] 2の累乗による割り算と右シフトは等価
- [迷信] FILE 型は構造体
- [迷信] abs は常に非負の値を返す
- [迷信] argv[0] はプログラム名
- [迷信] char 型は符号付き
- [迷信] double の出力書式は "%lf"
- [迷信] fflush で入力バッファをクリア
- [迷信] free でメモリを開放する
- [迷信] free に NULL を渡すとクラッシュする
- [迷信] gets は単純に fgets に置き換えられる
- [迷信] isalpha 関数の引数は char 型
- [迷信] new に失敗すると NULL が返る。
- [迷信] scanf ではバッファオーバーランを防げない
- [迷信] scanf でキーボードから入力
- [迷信] setjmp マクロの返却値は変数に代入できる
- [迷信] sizeof は定数式
- [迷信] void main(void)
- [迷信] とりあえず memset で初期化
- [迷信] アルゴリズム関数内で関数オブジェクトはコピーされない
- [迷信] オブジェクトの動的生成に失敗するとメモリリークする
- [迷信] コンストラクタから例外を送出してはならない
- [迷信] コンストラクタで自身をゼロクリア
- [迷信] コンパイラはプログラマの心を察してくれる
- [迷信] コンパイルエラーが出るのでアクセス指定子を修正
- [迷信] ソースコード中の即値を全廃せよ
- [迷信] ソースファイルの末尾に }
- [迷信] データ列のソートには qsort 関数を使うべし
- [迷信] プログラムは必ず main から始まる
- [迷信] 一重引用符の中には一文字しか書けない
- [迷信] 今どき int が 16 ビットの処理系なんて無い
- [迷信] 入力データ格納用配列のサイズは BUFSIZ
- [迷信] 割付けたメモリはプログラマが自分で解放しなければならない
- [迷信] 実数型とは浮動小数点型のことである
- [迷信] 引用符で囲んだヘッダ名はカレントディレクトリから探索する
- [迷信] 文字列から整数への変換には atoi
- [迷信] 構造体のタグ名は下線で始める
- [迷信] 構造体はクラスではない
- [迷信] 識別子に使える文字は英数字と下線のみ
- [迷信] 非局所オブジェクトは外部結合
- C言語再入門
- C言語徹底入門
- Drupal メモ
- TOPPERS 情報
- ライブラリ開発入門
- 分割コンパイルをきわめる
- 擬似プロセッサを作る
- 車輪の再発明
- 過去の情報

