staticは変数、関数、構造体変数に対して使える修飾子です。
staticを使うと変数などの有効範囲が限定され、変数値はプログラムの始めから終わりまで保持されます。
static変数(静的変数)とは
static変数とは頭にstaticを付けて定義した変数のことをいいます。
static変数は定義したファイル内でのみ使えます。
また、プログラム全体で値が保持されるという特徴があります。
値が保持される、つまり静的な変数なのでstatic変数は静的変数とも呼ばれます。
ローカル変数におけるstaticの使い方・初期化方法
使い方・初期化方法
staticを使うとプログラムを通じてローカル変数の値が保持されます。
ただし変数が使えるのは定義した関数内のみです。
例1のローカル変数をstaticを使って定義すると以下のようになります。
例1:
#include <stdio.h> void print_num(void); void main() { print_num(); print_num(); print_num(); } void print_num(void) { static int num=0; //staticローカル変数の定義・初期化 printf("num=%d\n",num); num=num+1; //numの値に1足す }
実行結果
num=0
num=1
num=2
初期化は定義と同時に行います。
static変数の初期化は一度だけ行われ、関数を出た後も値は保持されます。
よって例1ではprint_num関数を呼び出すたびにnumの値が増えます。
初期化は一度しか実行されませんが、代入は都度実行されます。定義時に初期化せず、後で「num=0;」のように初期値を代入すると関数に入るごとに値がリセットされてしまうので注意です。
staticローカル変数を初期化しない場合は自動的に初期値として0が入ります。
しかし後でコードを読んだ人が「初期値には何が入るんだ?何か意図があるのか?」と疑問を持ってしまうので例1のように明示的に初期化するようにしましょう。
また、static変数は定義された関数内でのみ有効なので、main関数からnumを呼び出すとコンパイルエラーになります。
staticローカル変数のメリット
ローカル変数の値を保持できる
グローバル変数もプログラムを通じて値が保持されますが、どの関数からも呼び出せてしまうので、思わぬタイミングで書き換えられてしまうリスクが高いです。
staticローカル変数は定義した関数でしか使えないので、トラブルを引き起こしにくいのです。
引数を使うよりプログラムが早い
引数の代わりにstatic変数を使うことで引数を作る処理がなくなるので、プログラム速度を早くできるというメリットもあります。
ただしstatic変数はプログラムの実行中常に保持されるので、static変数を多用するとプログラムが大きくなりがち(メインメモリの占有領域が多くなりがち)です。
グローバル変数におけるstaticの使い方・初期化方法
使い方・初期化方法
staticを付けて定義したグローバル変数は他のファイルから参照できないという特徴があります。
staticグローバル変数は以下のように同じファイル内でのみ参照します。
例2:
#include <stdio.h> static int NUM=0; //staticグローバル変数の定義・初期化 void main() { printf("NUM=%d\n",NUM); }
実行結果
NUM=0
通常、初期化は定義と同時に行います。
staticグローバル変数を初期化しない場合は自動的に初期値として0が入ります。
しかし後でコードを読んだ人が「初期値には何が入るんだ?何か意図があるのか?」と疑問を持ってしまうので例2のように明示的に初期化するようにしましょう。
staticグローバル変数のメリット
変数の有効範囲を制限できる
プログラミングにおいては変数にできるだけ制限を付けるのが鉄則です。
制限付けず、どこからでも書き換えできると意図しない値に書き換えられてしまう可能性があるからです。
大きなプログラムは複数人で開発するので、同僚が思いもよらない使い方をすることがよくあります。
1人で開発している場合でも何年か後にコードを見直すときにはどれがどんな変数か完全に忘れています。
制限を付けると確かに不便になるのですが、気づかないうちに意図しない動きをしていて損失を出すよりは遥かに良いのです。
staticは変数の利用範囲に制限を付けてミスを減らすための機能の1つなのです。
他ファイルで変数名が被ってもエラーにならない
通常は複数ファイルにて同じ名前のグローバル変数を定義するとリンク時にエラーになります。
同じ名前のグローバル変数は一度しか定義してはいけないというルールがあるからです。
しかしstaticグローバル変数なら複数ファイルで同じ名前のグローバル変数を定義できます。
staticグローバル変数どうしは同じ名前であっても全く異なる変数として扱われます。
複数ファイル間で同じグローバル変数を共有したい場合はexternを使います。
関数におけるstaticの使い方
関数に対してstaticを使うと、その関数は定義したファイル内でのみ呼び出し可能になります。
以下の例のstatic関数は同じファイル内からは呼び出せますが、別のファイルからは呼び出せません。
例3:
#include <stdio.h> static int plus(int x, int y){return x+y;} void main() { printf("3+2=%d\n",plus(3,2)); }
実行結果
3+2=5
返り値がないvoid関数にもstaticが使えます。
プロトタイプ宣言する場合はプロトタイプ宣言と関数の定義の両方にstaticを付けます。
構造体におけるstaticの使い方・初期化方法
構造体の宣言においてはstaticを使うことはできませんが、構造体変数を定義する際にはstaticが使えます。
例4:
#include <stdio.h> typedef struct //構造体の宣言 { int id; char name[30]; }person; static person sato={0,"Sato Hiroyuki"}; //staticを使って構造体変数の定義 void main() { printf("ID=%d, Name=%s\n",sato.id,sato.name); }
実行結果
ID=0, Name=Sato Hiroyuki
例ではグローバル変数を作りましたが、ローカル変数でもstaticが使えます。
staticとexternは同時に使えない
staticとは変数を定義したファイル内でのみ使えるようにする機能でした。
一方でexternはstaticと真逆で、変数を別ファイルでも使えるようにする機能です。
externについてはこちら
-
【C/C++】externとは?関数・変数・配列・構造体との使い方
複数のソースファイルで共通のグローバル変数を使いたい時に利用されるのがexternです。 通常、変数は宣言と定義が同時に行われますが、externを使うと定義は行わずに宣言だけを行えます。 exter ...
続きを見る
そのためstaticとexternを同時に使うことはできません。
例えば以下のようにextern宣言を使って複数ファイルでstatic変数を共有しようとするとコンパイルエラーになります。
例5:
main.c
#include <stdio.h> #include "head.h" static int NUM=0; void main() { printf("NUM=%d\n",NUM); }
head.h
#ifndef HEAD_H #define HEAD_H extern int NUM; //static変数はextern宣言できない void print_NUM(); #endif
sub.c
#include <stdio.h> #include "head.h" void print_NUM(){printf("NUM=%d\n",NUM);} //NUMは参照できない
実行結果
(static変数はextern宣言できないのでコンパイルエラー)
グローバル変数を複数ファイルで共有する際にはヘッダファイルでextern宣言をします。
しかしstatic変数は他ファイルから参照できないので、コンパイルエラーになります。
sub.cではNUMを使おうとしていますがこれもNUMがstatic変数なためできません。
staticを付ける目的は変数の有効範囲を制限してプログラムミスを減らすことでした。
しかしヘッダファイルでstaticを付けて宣言してしまうと、ヘッダファイルがインクルードされたファイルすべてでstatic変数が使えてしまい、staticにする意味がなくなってしまいます。
ヘッダファイルは複数のソースファイルでインクルードして変数宣言を何度も書かなくて良くする目的で作られているので、staticとは相性が悪いのです。
static変数はソースファイルごとに定義して使います。
C言語で行き詰まったら…
-
C言語・C++がわからない時に質問できるサイト・サービス5選
C言語を独学で勉強しているけど内容がイマイチわからない。もはや何がわからないのかもわからない。 C++のエラーが解決できない。ググってもわからない。わかる人に解説してほしい。 こんなお悩みにお答えしま ...
続きを見る