static領域って、具体的にどんな領域なのか調べてみた
stick stock static
オイラは歩く、歩く犬。
たまに棒に当たる犬。
オイラは歩く、歩く犬。
棒に当たると痛いんだ。
オイラはある日、閃いた。
棒を咥えて歩けば良いと。
オイラは棒と、共に歩く。
困難を味方につける、犬なのさ。
それが平穏の秘訣なんだ。
目次
1. そもそもstatic領域ってなに?
C言語や他の言語にもでてくるstatic領域。
それは一体何なのか。
よく、mallocのような動的配列の領域と比較されますが、これは「静的に」割り当てられています。
つまり、プログラムの実行開始前にメモリの特定の領域が予め確保され、その存続期間(または「範囲」)はプログラムの実行開始から終了まで保持される事を指します。
そしてその領域の事ををstatic領域と言います。
静的(static)領域と動的領域の違いは以下の通りです。
静的領域(Static Storage)
存続期間: 静的領域に確保された変数(グローバル変数やstaticキーワードを使用したローカル変数)の存続期間は、プログラムの実行開始から終了までです。
これらの変数はプログラムが終了するまでメモリに存在し続け、その値を保持します。
割り当て: 静的領域へのメモリ割り当ては「静的に」行われます。これは、プログラムのコンパイル時にメモリサイズが決定され、実行時には変更されないことを意味します。
静的領域はデータセグメントに含まれ、初期化されたデータ(初期化されたグローバル変数や静的変数)と未初期化データ(BSSセグメント)に分けられます。
コード例
#include <stdio.h>
int globalVar = 10; // グローバル変数(静的領域に確保される)
void function() {
static int staticVar = 20; // 静的ローカル変数(関数が終了しても値が保持される)
printf("Static variable: %d\n", staticVar);
staticVar++;
}
int main() {
printf("Global variable: %d\n", globalVar); // 10が出力
function(); // 関数を初めて呼び出す < 20が出力
function(); // 関数を2回目呼び出す < staticVar++も保持されているので21が出力
return 0;
}
動的領域(Dynamic Storage)
存続期間: mallocや関連する関数によって確保されたメモリ(ヒープ領域)の存続期間は、明示的にfree関数を呼び出してメモリを解放するまで、またはプログラムが終了するまでです。
プログラマは必要に応じてメモリを確保・解放することができます。
割り当て: 動的領域へのメモリ割り当ては「動的に」行われます。
これは、プログラムの実行中に必要に応じてメモリサイズが決定され、確保・解放されることを意味します。
この柔軟性により、プログラムは実行時に変化するデータサイズに適応できますが、メモリリークや断片化といった問題に注意する必要があります。
コード例
#include <stdio.h>
#include <stdlib.h>
int main() {
int *dynamicArray;
int size = 10; // 動的配列のサイズ
// 動的にメモリを割り当てる
dynamicArray = (int*)malloc(size * sizeof(int));
if (dynamicArray == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
return 1;
}
// 配列を使用する
for (int i = 0; i < size; i++) {
dynamicArray[i] = i * i;
printf("dynamicArray[%d] = %d\n", i, dynamicArray[i]);
// 0,0 ,, 1,1 ,, 2,4 ,, 3,9 ......のように出力
}
// 動的に割り当てたメモリを解放する
free(dynamicArray);
return 0;
}
要するに
静的領域はプログラムの実行全体にわたって存在し、コンパイル時にサイズが決まります。
反対に、動的領域はプログラムの実行中に確保・解放され、そのサイズは実行時に決まります。
2. 他の領域との違い
他にも様々な領域があるので、まとめてみました。
階層 | 内容 | 有効範囲 | 初期値 | 動的/静的 | 特徴 | 具体例 |
---|---|---|---|---|---|---|
テキストセグメント | 実行可能コード | プログラム全体(プログラムが終了するまで) | - | 静的 | 読み取り専用、コード格納 | int main() { /* ... */ } |
初期化されたデータセグメント | 初期化済みのグローバル変数、静的変数 | プログラム全体(プログラムが終了するまで) | 明示的に指定 | 静的 | グローバル/静的変数格納、プログラム実行中変更可能 | int globalVar = 100; |
未初期化データセグメント | 未初期化のグローバル変数、静的変数 | プログラム全体(プログラムが終了するまで) | 0(数値)、NULL(ポインタ) | 静的 | 初期値なしで宣言されたグローバル/静的変数格納 | static int staticVar; |
ヒープ | 動的に確保されたメモリ |
free() が呼ばれるまで、またはプログラムが終了するまで |
未定義 | 動的 | 動的メモリ割り当て、サイズ可変 | int *dynamicArray = malloc(10 * sizeof(int)); |
スタック | 関数のローカル変数、関数の引数 | 関数内(関数が終了すると解放される) | 未定義 | 静的 | 関数呼び出し/ローカル変数格納、LIFO順序 | int localVar = 5; |
因みに未初期化データセグメントはBSSセグメントと呼ばれ、Block Started by Symbolというアセンブラの疑似命令に由来するそうです。
アセンブラではこの命令を使って、プログラムが実行される際に一定の量のメモリを0で初期化する必要がある変数を定義していました。
つまり、BSSセグメントは、初期値を必要としないが、プログラムの実行時に確保されるべきメモリ領域を指定するために使用されていました。
ですが、プログラミング言語が進化するにつれて、意味が抽象化されていったそうな。
頭の片隅にでも。
3. おわりに
沢山の領域があって、知らず知らずのうちにそれらを使っていたんだな、と思いました。
これだけでもややこしいのだから、やはり、現実の社会問題である領土問題について考えると、より複雑になってくるのかなと思います。
せめて、心の領域だけは広くいよう、と思う自分なのでした~。