static/autoとは何か - 2024年度 システムプログラミング
static/auto とは何か
C言語から見た static と auto の違い
以下の1行目で宣言されている変数は,static(静的)変数, 一方,5行目で宣言されている変数は,auto(自動)変数であるという.
1: int primes_stat[10]; 2: 3: main() 4: { 5: int primes_auto[10]; 6: 7: primes_stat[0] = 2; 8: primes_auto[0] = 3; 9: 10: print_int(primes_auto[0];) 11: print_int(primes_stat[0];) 12: }
C言語のstatic変数は,以下の特徴を持っている.
- プログラムの開始から終了まで,値を保持しつづける.
一方,auto 変数は,以下の特徴を持っている.
- 関数の中で宣言され,その関数の実行開始時から 終了時までの間,その値を保持する.
この特徴の違いは,アセンブラ内でどのような記述の違いとして 生じているのかを調べてみよう.
static 変数のアセンブラ表現
report2-1.c と,それに対応する report2-1.s から primes_stat を探すと, アセンブラで,以下の行を発見する.
.comm _primes_stat,40
これは,
.data .align 2 _primes_stat: .space 40
と同等と考えてよい.つまりデータセグメント内にデータを40バイト確保している. この領域は,primes_stat のためだけに使用されるので, プログラムの開始から終了まで, 値を保持しつづけるという性質を持つことになる. いいかえれば,primes_stat は常にその領域しか使用しないので, 関数などが再帰的に呼び出された場合は,その領域を上書きすることがある. つまり,
- プログラムの開始から終了まで,値を保持しつづける一方で, 固定された領域(staticな領域)のみを使用するので, 再帰やスレッドによる並行処理では,上書きの危険がある.
といえる.
auto 変数のアセンブラ表現
一方,auto 変数である,primes_auto は, report2-1.c にはあるが,report2-1.s からそれらしい部分を簡単に発見することができない.
以下,抜粋:
1: $LC4: 2: .asciiz "primes_auto[0]" 3: .text 4: .align 2 5: 6: main: 7: subu $sp,$sp,64 8: sw $ra,60($sp) 9: sw $fp,56($sp) 10: move $fp,$sp 11: li $v0,2 # 0x2 12: sw $v0,_primes_stat 13: li $v0,3 # 0x3 14: sw $v0,16($fp) 15: la $a0,$LC3 16: lw $a1,_primes_stat 17: jal _print_var 18: la $a0,$LC4 19: lw $a1,16($fp) 20: jal _print_var 21: move $sp,$fp 22: lw $ra,60($sp) 23: lw $fp,56($sp) 24: addu $sp,$sp,64 25: j $ra
唯一,文字列だけから抜粋の02行目にみつけることができる.
これを頼りに手繰ると,18行目で $LC4
を使っていることから,
20行目で呼出している print_var
の第2 引数が primes_auto[0]
の値
であると分かる.つまり,19行目の $a1
,さらに遡ると
16($fp)
のことである. $fp
は 新$sp
と同じアドレスを指すので,
primes_auto
は 新$sp + 16
バイト目にあることが分かる.
つまり,スタック上に存在している.(各自スタックの絵を書いてみるとよい)
primes_auto
は,24行目の $sp
操作によって,
この関数呼出しが終わった瞬間に領域を開放して,値が使えなくなる.
main
関数における自動変数宣言は,
「関数の終了」=「プログラムの終了」に近いため,
変数の寿命についてあまり意識することはない.
C言語における static というキーワード
C言語において static
というキーワードは,2つの意味を持っているため,
誤解を生じやすい.1つは,上記で説明した,静的記憶クラスを使用するという指定である.
具体的にいうと,スタック上ではなく,プログラム中に静的に存在する領域にデータを確保するという意味である.
もう1つは, static
を付けるとスコープ(変数が外部から参照できる範囲)
が変化するということである.
具体的には,関数外(ファイルの先頭など)で static
を付けて宣言した変数は,
外部のファイルからは参照できない.
簡単にいうと,複数の .c ファイルから構成されるプログラムにおいて,
あるファイル内だけからしか参照できない変数を宣言できる.
このように static
が2つの意味を持つために,
static
の使い方を誤解している場合がある.
static
は,関数内でも有効に働くので,その場合はスコープ(変数の有効範囲)
ではなく,記憶クラスを指定するのだと理解して欲しい.
以下に宣言とその解釈の一覧を示す.
宣言例 | スコープ:見える範囲 | 記憶クラス(寿命) |
---|---|---|
static int a; (関数内) | 関数内 | 静的(プログラム中) |
static int a; (関数外) | ファイル全体 | 静的(プログラム中) |
int a; (関数内) | 関数内 | 自動(関数中) |
int a; (関数外) | プログラム全体 | 静的(プログラム中) |