C言語のstatic(http://d.hatena.ne.jp/propella/20070508/p1)

static local variableのstaticは「静的メモリ領域におかれた」という意味です。
C言語においてはブロックの内側で定義されたlocal variableはブロックスコープを外れたときに適宜破棄されるという仕様がありますが、多くはこれをスタックフレームやレジスタで実装しています。
これを何らかの理由でスタックフレームやレジスタにとってほしくないときにstatic修飾子を使います。静的メモリ領域は、大域変数などと同様に、ローダがスタートアップ時にメモリを確保し、エントリポイントに入る前にのみランタイムが初期化を行います。この初期化のタイミングのために、「ブロックを抜けても値が保持され続ける」という副作用が起こります。
「何らかの理由」としては

  • 変数をたくさんスタックフレームにとることによって、インデックス相対参照できなくなってはまる
  • 巨大な配列を取ってそもそもスタックがあふれる
  • っていうか、スタックがリターンアドレスだけでいっぱいいっぱいなほど狭い
  • そもそも、スタックみたいな不定長なメモリ領域を最低限しか取らない。使う変数はあらかじめ確定してないとメモリ内に実装が収まることを保証できない。

といった、実装依存な理由ばかりが考えられます。


これに対して、大域変数や関数に関するstaticは少し意味合いが異なります。この場合の「静的」とは、「シンボル情報を外部に求めない/外部からも参照されない」ということをさします。
C言語において、グローバルスコープにおかれたほとんどのものは、「シンボル」として外部からも参照されうるものとして考えます。ここでの「外部」は「コンパイル単位」に対する外部のことで、具体的にはリンク前の「オブジェクトファイル」を指します。
オブジェクトファイルをコンパイルする際、未解決なシンボルに関してはリンク時に解消するという前提で話を進めます。ただ、C言語は基本的に1パスでコンパイルを終了させるという実装上の理由があるため、「未解決なシンボル」なのか「未定義のシンボル」なのかが区別がつきません。
そこで、関数のプロトタイプ宣言などをして、「その関数がどこかにある。型はこんな感じ」ということをあらかじめ宣言した上で実際の呼び出しを行います。この宣言がそもそも「どこかにある」のではなく、「必ず同じオブジェクトファイルにある」ことを伝えるためのものがstaticです。逆に「外にある可能性がある」ことを示すのがexternです。
副作用として、外部にシンボルを解放しないということから、別のオブジェクトファイルに同じ名前のシンボルがあってもリンク時にシンボルの衝突が起こりません。これによってあたかも「ファイルをローカルな名前空間として扱う」ことができます。


……でも、このまったく意味の異なる2つのことに同じ予約語を割り当てたのは絶対C言語としては失敗だと思います。
たとえば、見習い魔導士である Florian の教え子は、だいたい学校に入って半年ぐらいでこの辺の話をプロセスの持つメモリ構造(コード、データ、スタックなどの領域)と、コンパイル単位(分割コンパイル)を叩き込まれた上でやっと教わります。けど、独学でやっていた子は大概この辺混同して酷い目にあってます(^^;)。
とくに、的確な大域変数の使用ができない子に限って、static local variableを使ってみたり(「大域変数を可能な限り使うな」という教えを曲解している)、無節操にstatic global variableを作って、コンパイル単位が膨れ上がった後で再分割できずにはまったり(設計していない人が下手に名前空間を使うと酷い目に)という傾向があります。
独学などで覚えたことを使うのはすばらしいのですが、少なくとも正確に理解するまでは、staticという文字列をgrepで見つける度に「このコード全部作り直しね」と地獄の宣告をしています。たとえ、何千行もあるソースであったとしても(^^;)。
まぁ、C言語の出自からして低レベル向けの少し便利なアセンブラを指向している為、明らかな実装依存の問題をクリアするための仕方のない仕様がいろんな歴史的経緯で混在しているという理由はわからないでもないのですが、あちこちにゆがんだ仕様を見る度に「これはどう納得してもらおうか」といつも悩んでいます。
確かにK&Rにも書いてはあるんですけど……酷くわかりづらいんですよね、これが(^^;)。