Commentsとある製品のソースコードを眺めていたときに疑問に思って調べたことをメモします。abc;という風に書かれています。一瞬、それぞれのモジュール(ソースファイル)に別々の実体が存在するのかな、と思ったのですが、実際のその製品の動きを見てみるとちゃんと変数を共有して使っているようです。私のいままでの理解が間違っているかもしれないので調べようと思ったのですが、C言語の規約を調べるのも億劫だし、環境依存かもしれないので、とりあえずサンプルを書いて手元のUbuntuのgcc(4.2.4)で挙動を調べてみました。次のような2つのソースファイルを用意し、コンパイルして実行してみました。(ヘッダファイルは作らずにそれぞれのソースに同じ変数宣言を書きました。./a.outb:value=1a:value=2ちゃんと共有されています。value;のところを、externのみにしたり、externの方を外したりしてみて共有されるか確認した結果は以下のとおり。共有される大域変数は暗黙でstaticにはならないので、やはり、コンパイルが通れば共有されますね。(よく考えれば当たり前ですが。value=0;のように初期化するとコンパイル(リンク)エラーとなります。here片方(1つ)のみ初期化する場合はエラーにはなりません。これらの結果からコンパイラとかリンカの挙動を想像すると、externのついた大域変数は必ずいずれかのモジュールに実体がないとダメで、externのつかない大域変数は基本的にexternありと同じだが、いずれのモジュールにも実体がなければリンカが実体を作る、という感じになるでしょうか。(あと、初期化をしたら必ずそのモジュールに実体が作られ、複数のモジュールに実体があればエラーとなる。)で、ここで疑問に思ったのですが、意図的に共有する場合はexternなしでもいいと思うのですが、それではたまたま他のモジュールにあるものと同じ(大域)変数名を使っていたら、意図せずに共有されてしまう、ということになります。いう状況になったら、かなり見つけにくいバグになりそうですね。(externとかstaticとか明示する習慣をつけておけば起こりにくい問題ですが。)というわけで、そうした問題を未然に防ぐコンパイル(リンカ)オプションを調べておきました。(このオプション、デフォルトでは無効のようです。hereexternのつかない同じ名前の大域変数を複数のモジュールで宣言するとこのようにwarningが出ます。hereこちらはコンパイル(リンク)エラーとなります。以上、知っているようで知らない(のは私だけ?)、C言語にまつわる小ネタでした。#今検索したら、同じことに悩んだ方が他にもいたようです。PMK&Rの第2版、A10.2に以下のような記述があります。初期値式をもたず、またextern指示子を含まない外部的なオブジェクト宣言は、仮の宣言(※)と呼ばれる。オブジェクトの定義が翻訳単位に現れると、仮の定義は単に冗長な定義として扱われる。そのオブジェクトに対する定義が翻訳単位に現れないときには、仮の定義はすべて、初期値0をもつ単一の定義になる。※は誤訳で、正しくは「仮の定義」。etc.)があれば、それが唯一の定義として扱われる(当然、複数の定義は許されない)というのが言語仕様通りの動作のようです。私も全然知りませんでした。明示的に宣言しておかないと、バグの素になりそうですね...。PMなるほど!言語仕様にちゃんと書いてあるんですね。フォローありがとうございます。確かに、ちゃんとextern等をつけないとバグの素になりそうなので、一般的な入門書にはこういう仕様は書かれていないのでしょうね。PMこのような言語仕様になった(externの省略が許されるよう緩和された)理由は、もともとUNIX他のオペレーティングシステムのリンカーがFortran言語を前提に作られている現状を追認するためなのではないかと思います。Fortranは上記の「初期値式を持つ定義」は許されない代わりに、extern宣言は不要ですから。fsさんコメントありがとうございます。Fortranの影響を受けているのですね。私はFortranについては「昔の言語」という程度の知識しかなかったのですが、勉強になりました。(調べたら、今でも進化しているようですね。)比較的新しい言語も、こういう歴史の古い言語の影響を受けていたりするので、古い言語を知っているのと知らないのでは理解の深さが違うだろうな、と思いました。コメントをキャンセルメールアドレスが公開されることはありません。*サイト次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。