[1051] Re:externと「外部結合」
投稿者:yuya
2007/09/02 16:34:38
774RRさん、(ぱ)さん、ありがとうございます。
たくさんコメントをいただいたので、[1045]~[1050]へのリプライは
こちらにまとめさせていただきます。
[1048]774RRさん;
> ながながと書いたけど結局のところ yuya さんの疑問点は
> extern 記憶域指定子はなぜに (6.2.2) のようなヘンな振る舞いをするのか、その根拠やいかに
> ということでよろしいのだろうか?
[1049](ぱ)さん;
>>static int i2 = 2; // 定義,内部結合
>>extern int i2 ; // 内部結合をもつ前の定義を参照する
>
> この「extern int i2;」の挙動が不可解だということですよね。
> 私にも不可解に見えます。そもそもキーワードの名前が「extern(al)」なのに!
6.2.2のexternの振る舞いが奇妙に映るのは、(ぱ)さんのおっしゃるとおり、
`extern'という、外部結合(external linkage)を想起させる名前によるところが大きいと思います。
いったん名前のことを忘れて、単に
「(翻訳単位内外にかかわらず)どこかで定義されている(かもしれない)変数・関数を参照する」
という機能が主眼だと考えれば、6.2.2の結合の定まり方は、
「可能な限り状況に合わせて結合を決定する」という、ある意味ではきわめて合理的な、
悪く言えば御都合主義的な仕様になっています。
その背景には[1048]・[1050]で774RRさんが書いてくださったような事情があった可能性が高いと思います。
現在の目から見て、初心者に「結局のところexternって何をするんですか?」と聞かれたとき、
最も正しい答えは[1046]でまとめていただいたように規格書の該当箇所を指し示すことだと思いますし、
最終的には本人にそこまで行き着いてもらわないといけないわけですが、
やはり(自分自身の頭を整理するためにも)「何が原則で、何が例外か」という観点で整理したくなり、
できるだけ普遍的な原則・少ない例外で理解できる方法はないだろうか、と思ってしまうわけです。
その過程の中で、歴史的経緯を知ることが原則を抽出する助けになることも多いと思います。
もちろん規格書には「これが原則、これが例外」などということは書かれていませんから、
注意しないと私が陥ったように勝手な行間解釈や俺俺用語を生んでしまうわけですが……。
で、実際にexternに対してそのような整理を試みたとき、ポイントとなる切り口は
[1047]でご指摘のとおり「結合は何か」「定義になるかどうか」です。
ここでexternという名前を尊重して、「結合指定」を原則に据えると、
内部結合になるケースを例外と捉え、「定義になるかどうか」は別途論じることになります。
これに対して、「定義にならない」ことを原則に据えると、
(a); 結合は上記のように状況に合わせて定まる。
(b); 何も付けなくても初めから外部結合のブロック外定義になっているもの
(関数定義や初期化子つきのブロック外変数定義)だけは、externをつけても定義とみなされる。
extern int hoge = 1; /* 外部結合のブロック外定義 */
と整理することができ、(b)が昔はコンパイルエラーになっていたとなれば、
例外として扱うことへの抵抗が小さくなります。
結局のところ、Cの振る舞いを統一的に理解することなど追求すべきでないのかも知れず、
[1045]774RRさんの
> なんか難しく考えすぎなのではないかと思ってきた・・・
が最も正しいような気がしてきました。自覚はあるんですけど(^^;)