『Cプログラミング専門課程』目次第4章メモリ

4.5 静的記憶領域 (1)


プログラム実行中は、色々なものがメモリ上に存在します。プログラムが起 動し、終了するまでメモリ上の一定の位置に存在し続けるものに、プログラム とデータの一部があり、データの方だけを指して「静的記憶領域」と呼びます。

静的記憶領域というのは非常に理解しやすいものです。

次のプログラムで実際に変数のアドレスをプリントしてみましょう。各変数 のアドレスが状況によってどう変化するか比べてください。

サンプルプログラム

   1: /*  static.c -- 静的記憶領域/変数のアドレス  */
   2: 
   3: #include        
   4: 
   5:         int     glob;
   6: static  int     stat;
   7: 
   8: void    printvaraddr( void )
   9: {
  10:         printf( "グローバルな変数     [A] %p\n", &glob );
  11:         printf( "外部的にstaticな変数 [B] %p\n", &stat );
  12: }
  13: 
  14: void    func( int p )
  15: {
  16:         static  int     s;
  17:                 int     loc;
  18: 
  19:         printf( "--> 関数 func の呼び出し\n" );
  20:         printvaraddr();
  21: 
  22:         printf( "関数のパラメータ     [C] %p\n", &p );
  23:         printf( "関数内のstaticな変数 [D] %p\n", &s );
  24:         printf( "関数のローカル変数   [E] %p\n", &loc );
  25: 
  26:         {       static  int     ss;
  27:                         int     tt;
  28: 
  29:                 printf( "内部ブロック内のstatic変数 [F] %p\n", &ss );
  30:                 printf( "内部ブロック内の変数       [G] %p\n", &tt );
  31:         }
  32:         printf( "<-- 関数 func の終了\n" );
  33: }
  34: 
  35: void    middle( void )
  36: {
  37:         printf( "--> 関数 middle の呼び出し\n" );
  38:         func( 100 );
  39:         printf( "<-- 関数 middle の終了\n" );
  40: }
  41: 
  42: main()
  43: {
  44:         printvaraddr();
  45:         func( 100 );
  46:         middle();
  47: }

実行結果
グローバルな変数     [A] 40c0
外部的にstaticな変数 [B] 40e8
--> 関数 func の呼び出し
グローバルな変数     [A] 40c0
外部的にstaticな変数 [B] 40e8
関数のパラメータ     [C] f7fffaac
関数内のstaticな変数 [D] 40d8
関数のローカル変数   [E] f7fffa5c
内部ブロック内のstatic変数 [F] 40e0
内部ブロック内の変数       [G] f7fffa58
<-- 関数 func の終了
--> 関数 middle の呼び出し
--> 関数 func の呼び出し
グローバルな変数     [A] 40c0
外部的にstaticな変数 [B] 40e8
関数のパラメータ     [C] f7fffa44
関数内のstaticな変数 [D] 40d8
関数のローカル変数   [E] f7fff9f4
内部ブロック内のstatic変数 [F] 40e0
内部ブロック内の変数       [G] f7fff9f0
<-- 関数 func の終了
<-- 関数 middle の終了

各変数のアドレス表示にA,B,C...の記号をつけました。 A,B,D,Fのアドレス は不変ですが、C,E,Gは変化しています。アドレスも完全に離れています。整 理すると、次のようになります。

  アドレスが「固定」の変数
        A      グローバル変数
        B      外部的にstaticな変数
        D      関数内のstaticな変数
        F      内部ブロック内のstaticな変数

  アドレスが「変化」する変数
        C      関数のパラメータ
        E      関数のローカル変数
        G     内部ブロック内の変数
  
ここでは、アドレスが固定の変数について注目していきます。

分類によると、static宣言された変数とグローバル変数だけが固定です。関 数func内のstatic宣言されていないローカル変数(auto変数)は、mainから直 接呼ばれたとき(main → func)と、main → middle → func の順に呼び出 されたときとではアドレスが変化しました。これについては後述します(4. 7スタック領域)。

関数のパラメータでも内部のローカル変数でもない変数で、staticがついて いないものを「グローバル変数」あるいは「広域変数」と呼びます。

staticはついていないが、externがついているものもグローバル変数ですが、 別のコンパイル単位でグローバル変数として宣言されているものを示しており、 「外部参照」と言います。この詳細は後述します(4.9 extern)。

staticがついた変数で、関数の外にあるものは「外部的にstaticな変数」と 呼ばれます。

関数の外部に存在する変数の形態は次の3種類になります。

            int     a;      グローバル変数
    extern  int     b;      グローバル変数(外部参照)
    static  int     c;      外部的にstaticな変数
  

関数の外部に書かれた変数は、たとえどのような修飾子(extern, static) が付加されようと、あるいは何もつかなくても、必ずアドレスは固定です。

staticがついた変数は、関数の外部にあろうと、関数の内部にあろうと、関 数の奥深いブロック中にあろと、その存在位置とは全く無関係に、その変数の アドレスは固定です。

関数中でstatic宣言をした変数も実行中にアドレスが変化することはなく、 「静的記憶領域」に確保されます。では、これをさらに確認するプログラムを みてみましょう。

⇒⇒⇒⇒次ページへ


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング専門課程』目次第4章メモリ