K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[1042] externと「外部結合」
投稿者:yuya
2007/08/30 16:42:41

別スレッドを立てました。 externと「外部結合」については以前から私の悩みの種で、 現時点で以下のように理解しているのですが、問題がないかどうか、よろしければご意見をお聞かせください。 以下、すべてブロック外の話で、「宣言」とは「定義でない宣言」を指すとします。 extern宣言は、同一翻訳単位内にすでに定義があれば、その結合に従った宣言となります。 定義がなければ他の翻訳単位に定義があるだろうと仮定して、 それに対応する宣言になろうとします(この場合には、状況から外部結合しかあり得ません)。 このようにextern宣言の振る舞いを見ると、externは 「近いところから順に定義を探し、状況に合わせて(きわめて自然に)結合が定まる」 宣言であると考えられます。 もちろん、実際にはほとんどのケースで外部結合になり、 内部結合になるのは同一翻訳単位内にstatic定義がある場合だけですが、 これを「例外」と捉えるよりも、上記のように結合が定まると考えたほうが良いように思います。 初期化子のない変数定義・宣言を考えたとき、記憶クラス指定子をつけなければ外部結合の仮定義になりますが、 これが(他に定義があるために)宣言に成り下がった場合でも、外部結合であることは動きません。 したがって、 static int hoge = 1; /* 定義(内部結合) */ int hoge; /* 仮定義(外部結合)、ここでは宣言になるが、結合指定が定義と矛盾する */ は未定義動作になります。これに対し、2行目にexternをつけた static int hoge = 1; /* 定義(内部結合) */ extern int hoge; /* 宣言(結合は状況に応じる)、ここでは定義に従い内部結合となる */ は問題ありません(ソースを比較すると、後者のほうが「問題あり」に見えてしまいますが)。 これを「結合」という観点から見ると、「絶対に外部結合」だったものが、 externを付けることで「結合は状況に合わせる」に変わっています。 ではexternの実際の機能は何かというと、 「私は定義ではなく、ただの宣言である。定義はほかにある」ことを明示することにあります。 [1024]ひげおやじさんの > 「別のところにあるのを宣言する」ってのはexternの本質を表していないのですね。 において、「別のところ」というのが「翻訳単位外」を指しているならば、確かに誤りです。 しかし、その「誤りである理由」は、「外部結合が『翻訳単位内も含む』概念だから」ではなく、 「externが(結合とは無関係に)翻訳単位内外両方に定義を探しに行くから」ではないでしょうか。 そもそもリンケージが翻訳単位外に及ぶ(つまり外部結合)、というのと、 宣言が定義を探しに行く範囲が翻訳単位外に及ぶ(extern宣言)、というのは 分けて考えるべきだと思うのですが、皆様のご意見はいかがでしょうか? なお、ブロック外において明らかに定義と分かるもの(関数定義や、初期化子の付いた変数定義)に externが付いた場合、外部結合になりますね(付けなくても同じですが)。 この場合はexternが文字通り「外部結合」を意味していると考えられますが、 ANSI以前はコンパイルエラーになっていたと聞いたことがあります。
[この投稿を含むスレッドを表示] [この投稿を削除]