パスワードを忘れた? アカウント作成
12746562 journal
日記

m_nukazawaの日記: C言語のstatic関数がファイルスコープになる理由を教えて! 10

日記 by m_nukazawa

ください。

C言語で関数にstaticを付けると、関数のスコープが"ファイルスコープ"になって、スコープ外で関数名が重複しても問題が起こらない、という話について。

staticの意味が、関数と変数のどちらに付けるかによって違う。

何かご存知の方がいらっしゃれば、教えていただければ幸いです。
歴史的経緯が特に知りたいです。

解説サイトなどでは、
『関数に付いたstaticはlocalだと思え』
という、C言語のお約束だ、呪文だと思ってください、天と地があり、太陽は東から登って西から沈むものだ、という説明しか見当たりません。
まるで、イントメインとインクルド・スタドアイオーもそうだったじゃないですか、変数とは箱です。ポインタとは箱の箱で...という、ありがちなC言語初心者向け解説のような。

以下妄想。
変数のstatic = 実行中は値を保持し続けるところから。
staticな変数や関数にはグローバルなメモリ位置が割り当てられる。メモリ位置が決まっているstatic関数はリンク時に関数名から呼び出したい関数を探す必要がない、よって同名の関数が複数あっても混同することがそもそも無い。...といったあたりが初期のCコンパイラの挙動で、static関数がファイルスコープになるというのはその時代からの互換性による名残り、という説はどうでしょう。

そういえばファイルスコープって、Cソースとオブジェクトファイル、どちらの"ファイル"なんだろう?

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by Anonymous Coward on 2016年04月09日 14時36分 (#2994682)

    変数も関数もそこは同じです

  • http://www.gotw.ca/publications/c_family_interview.htm [www.gotw.ca]

    Ritchie: I added some things under some pressure from users that I don't think were done well.
    (snip)
    The "static" keyword is very strange, expressing both a storage lifetime and what the standard calls "linkage" (external visibility).

    ユーザーの圧力が原因だそうで…。

    > そういえばファイルスコープって、Cソースとオブジェクトファイル、どちらの"ファイル"なんだろう?
    インタビューの通り linkage 単位ですね。
    Cソース単位にならない例として、
    include されるファイルで static な変数を定義して include する側で参照したりできます。

  • by Arimac (10826) on 2016年04月09日 23時19分 (#2994911) ホームページ 日記

    オフトピですが、autoな関数とか出来るようにしてたら今時世の中変わってたかも(^^;
    今やるとデータ実行になってしまいますが(^^;

    ラベルのポインターが取れて
    lb100:
        void *aaa = &lb100;
        goto *aaa;
    とか出来てると今頃C言語は捨てられてたかも(^^;

  • by Anonymous Coward on 2016年04月09日 17時52分 (#2994748)

    Cのstaticの意味に混乱があるのは規格化されるまえの既存プログラム
    をなるべく救おうとしたからじゃないでしょうか。

    関数がファイルスコープを意味するというのは、むかしの規格票しか
    いまは手元にないのでいまのはちがっているかもしれませんが、
    6.2.2 識別子の結合で決まっています。staticがある場合は内部結合
    になります。関数は外部定義(6.9)にあたりますが、これは外部定義
    のオブジェクト(変数)とおなじです。

    ついでですが、変数がちがうと言われるのは記憶期間の指定となる
    staticのことを言われているのだとおもいますが、これは6.2.4で決
    まってます。たしかにべつの話です。

    Cはその動く仕組みが丸見え的なところがあって、もともとの
    staticやexternの仕組みはリンカの仕組みそのままという感じです。
    リンカの仕様から考えると、staticな変数は.dataセグメントとかに割当
    たる固定領域のメモリ(つまり静的記憶期間)で、そのシンボル情報が
    エクスポートされるか(つまり外部結合か内部結合か)のコントロールは
    extern宣言として個別に制御できると自然なのですが、規格化されるとき
    におそらく既存の仕様をまとめてこうなったのでしょう。
    まあ、外部定義なら静的記憶期間かつ外部結合または内部結合かしかない
    のだから、問題ないわけです。

    また、いわゆるファイルスコープは外部定義の内部結合でしょう。
    これは翻訳単位です。

    • staticは予約語にしてたけどlocalやprivateはそうじゃなかったので使ってしまった既存のソースの事を考えて新たに識別子に出来なかったような気がする(^^;
      気にする人は
      #define local static
      #define private static
      とかしてね(^^;
      という積もりだったのかも。

      親コメント
    • by Anonymous Coward

      C言語をalgol風の再帰呼び出し可能な言語にすることを決めた時、呼び出し時に関数内で自動で確保される変数と静的に確保される変数を区別する必要が発生しましたが、
      大域変数は最初から静的に確保した領域に割り付けるつもりだったと思いますよ。
      Cのストレージクラス指定子は記憶場所(.dataセグメントやスタック等)を指定するための物とスコープを制御する物が入り混じっています。
      変数のインスタンスを同一にするために外部参照の宣言としてexternが必要ですが、大域変数では記憶場所を示すストレージクラスの指定子としてのstaticは必要なかったはずです。
      ではどうしてstaticを内部結合を示す指定子に使用したかということですが、あまり深い理由があった訳でもないんじゃないでしょうか。
      昔のことなので、キーワードが増えると字句解析が遅くなるとか考えて、既存のキーワードを使いまわしたとか・・・

      • by Anonymous Coward

        Cはstaticとして定義されたグローバル変数をextern宣言
        できます。これは内部結合になります。
        単純にexternが外部参照の宣言になるわけではありません。
        自然でないとはこういうことです。

        おっしゃる通りグローバルは静的記憶期間しか持ちようが
        ありません。じゃあexternだけでいいじゃんというのが
        リンカの仕様とかを知っていれば自然ですが、
        そうなってません。と、言いたかった。
        で、少なくとも規格化時点では、考えていないわけではなく、
        そうする理由があったとPlaugerが書いた記事を読んだ気が
        するのですが、20年以上前の雑誌記事なので探しきれません。

typodupeerror

私はプログラマです。1040 formに私の職業としてそう書いています -- Ken Thompson

読み込み中...