プログラミング系 Q&A 3


Index
  1. malloc(0) の振る舞いは?
  2. malloc() した後 free() せずにプログラムを終了するのはまずいのか?
  3. C では、関数内で宣言した自動変数はスタック上に確保されるのか?

1. malloc(0) の振る舞いは?

malloc(0) の動作は処理系依存であり、NULL を返すかユニークなポインタを返すかのいずれかになる (ISO/IEC 9899:1990 7.10.3)。処理系に依存するため、特定の動作を期待したプログラムは書かない方が良いだろう。

ちなみに、malloc(0) がユニークなポインタを返す場合は、malloc() がふつうに返すポインタと同じで、malloc() が管理する領域に "少なくとも 0 バイト" の領域を作ってその先頭のアドレスを返すだけである。NULL を返さない理由としては、

  1. n バイトの領域を確保する
  2. その n バイトの領域を使う
  3. 最後にその n バイトの領域を解放する

という一連の処理で、n が 0 か 1 以上かで場合分けしなくてすむようになるから、というのが考えられる。


2. malloc() した後 free() せずにプログラムを終了するのはまずいのか?

問題ない。

malloc() で割り付けた領域は、不要になった時点で free() すべきである。しかし、プログラムの終了時の free() は有害無益であり、それを理解しようとせずに短絡的に malloc() したものは free() する、という表面的な規範に従って満足しているアンチプロフェッショナルな態度は鬱陶しいとも言える。

malloc() で割付けた領域を OS に返すことについては、ISO/IEC 9899 や JIS X 3010 などの C 言語規格では一切述べていない。それどころか、malloc() で割付けた領域を解放しなければならないとも規定していない。

malloc() で割付けた領域を解放しなければならないと規定されていないので、解放せずに終了するプログラムでも strictly conforming program といえる。

conforming hosted implemetation は、すべての strictly conforming program を受け付けなければならないので、malloc() で割付けた領域を解放せずに終了するプログラムも受け付けなければならない。

さらに言えば、conforming hosted implementation は strictly conforming program を何回実行しようとも、ダウンしたり動作が不安定になったりしないものである、という仮定は合理的な仮定であると考えられる。

受け付けた結果、プログラム終了後に何が起こるかは規格の範疇外であり、その実装の環境 (OS など) で規定されるべきことである。例えば、malloc() したメモリーを free() せずに終了した場合、

  1. UNIX、MS-DOS、Windows95/98/NTならメモリーリークは起きない
  2. ANSI Cならメモリーリークは起きない
  3. (malloc()/free() という関数仕様から) まともな OS とまともな言語処理系の組み合わせならメモリーリークは起きないと期待してよい
  4. 上記のいずれでもない環境ではメモリーリークを起こす可能性がある (しかし free() したからといってメモリーリークが起きないとは保証できない)

逆に、例えば Windows の Win16 API で GlobalAlloc/GlobalFree を使い、GlobalFree を呼び忘れた場合はメモリーリークとなるが、これは malloc()/free() とは別の話である。

また、malloc() 相当のものが共有メモリーの割り当てと等価になっている OS があるそうで、この環境で free() 相当の関数を呼び忘れるとメモリーリークを起こす可能性はある。ただし、用意されている関数が malloc()/free() である可能性は低い。

さらに、組み込み用の OS では "ヒープの管理は全部アプリケーション側でやってね" と言うスタンスのものが少なくないそうだ。この環境で free() 相当の関数を呼び忘れるとメモリーリークが起きるだろうが、これも用意されている関数は malloc()/free() である可能性は低いと思われる。たとえ、malloc()/free() であっても、ANSI C 仕様に準拠している可能性はなさそうだ。

なお、Windows のリソ−スリークの話は、メモリーリークとは関係ない。たとえ、malloc() したメモリーを全て free() しても、リソースリークは起こりえる。


3. C では、関数内で宣言した自動変数はスタック上に確保されるのか?

そのような決まりはない。そういう C コンパイラが多いだけである。

規格では、

  6.1.2.4 Storage durations of objects
  [...]
    An object [...] has automatic storage durations.  Storage is
  guaranteed to be reserved for a new instanace of such an object
  on each entry into the block with which it is associated, or on
  a jump from outside the block to a labeled statement in the
  block or in an enclosed block.  [...] Storage for the object is
  no longer guaranteed to be reserved when execution of the block
  end in any way.  (Entering an enclosed block suspends but does
  not end execution of the enclosing block. Calling a function
  suspends but does not end execution of the block containing the
  call.)  [...]


  JIS X3010 
  6.1.2.4 オブジェクトの記憶域期間

  無結合を持ち、かつ記憶域クラスstaticをもたずに宣言された識別子の
  オブジェクトは、自動記憶域期間(automatic storage duration)をもつ。
  それが宣言されているブロックへ正常に入るごとに、又は外側の
  ブロックからそのブロック若しくはそのブロックの内側のブロックの中の
  名札付き文へ分岐するごとに、自動記憶域期間をもつオブジェクトの
  新しい出現のために記憶域を確保することを保証する。

以上、スタックという語は全く出てこない。




Index