はじめに
C言語を学んでいると、こんなコードを見かけることがあります。
static int count = 0;この static 、初心者のうちはかなり分かりにくいです。
初心者さん何が「static」なの?普通の変数と何が違う?



なぜ値が保持されるの?



ローカル変数なのに消えない?
こうした疑問を持つ人は非常に多いです。
この記事では、C言語の static変数 について、
- ローカル変数との違い
- 値が保持される理由
- スコープとの関係
- 実際の使いどころ
- 注意点
まで、図解イメージ付きで分かりやすく解説します。
C言語文法解説シリーズ
本記事は「C言語文法解説シリーズ」の1つです。
C言語の文法を、組み込み開発の視点も交えて解説しています。
C言語文法解説シリーズ一覧はこちら


C言語の文法を基礎から体系的に解説するシリーズです。
- ローカル変数とは?
- グローバル変数とは?
- static変数とは? ← 今回
- 記憶域期間とは?
- スコープとは?
static変数とは?
static変数とは、「関数終了後も値を保持し続ける変数」です。
例えば通常のローカル変数は、関数が終わると消えます。
しかし static を付けると、関数終了後も値が保持されます。
staticの文法的な使い方についてはこちらの記事で解説しています。


普通のローカル変数との違い
まずは通常のローカル変数を見てみます。
#include <stdio.h>
void func(void) {
int count = 0;
count++;
printf("%d\n", count);
}
int main(void) {
func();
func();
func();
return 0;
}実行結果:
1
1
1
なぜ毎回1になるの?
これは、
int count = 0;が毎回作り直されるからです。
関数が呼ばれるたびに、
count生成
↓
0で初期化
↓
count++
↓
関数終了で消滅
が起きています。
ローカル変数についてはこちらの記事で解説しています。


static変数にするとどうなる?
次は static を付けます。
#include <stdio.h>
void func(void) {
static int count = 0;
count++;
printf("%d\n", count);
}
int main(void) {
func();
func();
func();
return 0;
}実行結果:
1
2
3
なぜ値が保持されるの?
static を付けると、
static int count = 0;はプログラム全体で1回だけ生成されます。
つまり、
最初の呼び出し
↓
count生成
↓
0で初期化
↓
値保持
次回以降
↓
前回値をそのまま使用
になります。
スコープはローカルのまま
初心者が混乱しやすいポイントです。
static変数は、
- 値は保持される
- でも見える範囲はローカルのまま
です。
つまり、
void func(void) {
static int count = 0;
}の count は、
- func() の外からは見えない
- でも値は消えない
という特殊な性質を持っています。
スコープについてはこちらの記事で解説しています。


「見える範囲」と「生存期間」は別
スコープ
→ どこから見えるか
記憶域期間(生存期間)
→ いつまで存在するか
static変数は、
| 項目 | 内容 |
|---|---|
| スコープ | 関数内 |
| 生存期間 | プログラム終了まで |
です。
これを混同すると、staticが分からなくなります。
記憶域期間についてはこちらの記事で解説しています。


static変数の主な用途
① 呼び出し回数カウント
void func(void) {
static int count = 0;
count++;
printf("呼び出し回数: %d\n", count);
}かなり定番。
② 状態保持
int get_state(void) {
static int state = 0;
state++;
return state;
}前回状態を保持できます。
組み込み開発ではよく使われます。
③ 一時的な内部データ保持
関数内だけで使いたいが、
- 毎回初期化したくない
- 値を保持したい
場合に便利です。
static変数の注意点
① 状態が見えにくくなる
static変数は便利ですが、「前回状態を保持する」という性質上、
プログラムの動きが追いにくくなる場合があります。
例えば:
void func(void) {
static int count = 0;
count++;
printf("%d\n", count);
}この count は関数を呼ぶたびに増えていきます。
しかし、コードを読む側からすると、「なぜ値が変わっているのか」
が分かりにくいことがあります。
特に規模が大きいプログラムでは、
- いつ変更された?
- 何回呼ばれた?
- 初期状態は?
が追跡しづらくなります。
② バグ原因になりやすい
static変数は、関数終了後も値が残るため、
「前回実行の影響」を受けます。
例えば:
void process(void) {
static int initialized = 0;
if(initialized == 0)
{
printf("初期化\n");
initialized = 1;
}
}これは初回だけ初期化したい場合に便利です。
しかし、「なぜ2回目以降動かないのか」
が分かりにくくなることがあります。
初心者は、関数に入るたびに最初から実行される
と思いがちなので、混乱しやすいポイントです。
③ 再入性(リエントラント性)に注意
これは組み込みでかなり重要です。
例えば:
int get_next(void) {
static int value = 0;
value++;
return value;
}この関数は、内部状態を保持している
ため、同時実行に弱いです。
例えば割り込み処理
通常処理中
↓
value更新中
↓
割り込み発生
↓
同じ関数実行
すると、値が壊れる可能性があります。
割り込みでの変数操作の危険性についてはこちらの記事で解説しています。


マルチスレッドでも危険
複数スレッドから同時アクセスすると、
競合(Race Condition)が発生する場合があります。
そのため、
- mutex
- 排他制御
- volatile
- atomic処理
などが必要になることもあります。
④ テストしにくくなる
static変数は状態を保持するため、前回テストの結果が残る
ことがあります。
例えば:
func();
func();とすると、1回目と2回目で結果が変わる
ため、テスト条件を揃えにくくなります。
⑤ 「便利だから使う」は危険
初心者は、「値が保持できて便利!」
と感じて多用しがちです。
しかし、static変数を増やしすぎると、
- 状態依存が増える
- デバッグしにくい
- 挙動が分かりにくい
- 再利用しにくい
という問題が起きます。
static変数は「状態を持つ」
つまりstatic変数は、関数を「ただの処理」ではなく
「状態を持つ存在」に変える
ということです。
ここを理解すると、static変数の本質がかなり見えてきます。
変数を使った状態遷移の設計についてはこちらの記事で解説しています。


static変数はメモリ上どこに置かれる?
static変数は通常、
.data領域.bss領域
に配置されます。
通常のローカル変数(スタック領域)とは異なります。
.data領域と.bss領域については以下の記事で詳しく解説しています。




一方でローカル変数はスタック領域に置かれます。
スタック領域についてはこちらの記事で解説しています。


ローカル変数との比較まとめ
| 項目 | ローカル変数 | static変数 |
|---|---|---|
| 値保持 | されない | される |
| 生存期間 | 関数実行中のみ | プログラム終了まで |
| スコープ | 関数内 | 関数内 |
| 主な領域 | スタック | data/bss |
まとめ
static変数は、「スコープはローカルのまま、値だけ保持される変数」です。
特に重要なのは、
- スコープ
- 生存期間
を分けて考えることです。
初心者のうちは混乱しやすいですが、ここを理解するとC言語の理解が一段深くなります。
組み込み開発でも非常によく使われるため、しっかり理解しておきましょう。
この記事が参考になった方へ
スコープを含むC言語の基本文法をこちらの記事で整理しています。


エンジニアとして技術を学ぶことは重要ですが、
キャリアや副業についても同時に考える必要があります。
副業の現実や市場価値、今後のキャリア戦略については、
こちらの記事でまとめています。


技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。
小さなご相談からでもお気軽にご連絡ください。






コメント