C++ static グローバル変数と静的ローカル変数とか色々ぐちゃぐちゃなので書いて覚える初心者自己中記事
(注)externはまだ混乱するので今のぐちゃぐちゃが解決してから考える。
関数の外で宣言された変数はグローバル変数
どこからでも使用可能でプログラムが終了するまで保持される。
--------------------------------------------
int gh;//グローバル変数宣言
void Test(){
gh += gh;
cout << gh << endl;//二回目・三回目
}
int main(){
++gh;
cout << gh << endl; //一回目
Test();
Test();
cout << gh << endl;//四回目
}
(結果)
1
2
4
4
--------------------------------------------
確かに全部反映されている。
さらにグローバル変数と同名の変数が作られた場合。
--------------------------------------------
int gh;//グローバル変数宣言
void Test(){
gh += gh;
cout << gh << endl;//二回目・三回目
int gh = 100;//Test関数内で同じ名前の変数を宣言
gh += gh;//Test内の変数として認識している
cout << "Testで宣言したgh :" << gh << endl;
}
int main(){
++gh;
cout << gh << endl; //一回目
Test();
Test();
cout << gh << endl;//四回目
}
(結果)
1
2
Testで宣言したgh :200
4
Testで宣言したgh :200
4
--------------------------------------------
Test関数内でグローバル変数と同じ名前の変数を作成して、それに計算・表示をさせて見た。
結果は同名のローカル変数を宣言する前の処理はグローバル変数で行われていて、
宣言後はローカル変数の処理になった。
Test関数を二回呼び出しているけど動作は同じ。
ではローカル変数宣言後にグローバル変数を操作したい場合はというと
--------------------------------------------
int gh;//グローバル変数宣言
void Test(){
gh += gh;
cout << gh << endl;//二回目・三回目
int gh = 100;
gh += gh;
cout << "Testで宣言したgh :" << gh << endl;
::gh += ::gh;
cout << "グローバル変数::gh :" << ::gh << endl;
}
int main(){
++gh;
cout << gh << endl; //一回目
Test();
Test();
cout << gh << endl;//四回目
}
(結果)
1
2
Testで宣言したgh :200
グローバル変数::gh :4
8
Testで宣言したgh :200
グローバル変数::gh :16
16
--------------------------------------------
変数名の前に :: をつけるらしい。
ちゃんと動いてる。
グローバル変数は静的変数に分類されるのだそうだ。
静的ローカル変数も静的変数に分類される。
今のところぼんやり分かるのは、グローバル変数と静的ローカル変数の違いはスコープが違うという事だけ・・
最初はグローバル変数と静的ローカル変数を聞いた時に、どっちも静的変数ってことは静的ローカル変数もどこからでも使える!!と勘違いした。
実際やって見たら全然違くて
--------------------------------------------
void Test(int stint){
--stint;
cout << "Test関数内 " << stint << endl;
}
int main(){
static int stint = 100;
Test(stint);
cout << "main関数内 " << stint << endl;
}
(結果)
Test関数内 99
main関数内 100
--------------------------------------------
これはただ値をコピーしているだけだし
--------------------------------------------
void Test(){
--stint;//[error]
cout << "Test関数内 " << stint << endl;
}
int main(){
static int stint = 100;
Test();
cout << "main関数内 " << stint << endl;
}
--------------------------------------------
引き値なしでTest関数側で直接 stint をいじろうとするとエラーになるし。
ここでようやく static はグローバル変数にするものじゃないんだと気づく。(テキストが頭に入ってないバカ)
じゃあ static って何?
静的ローカル変数にするものですよね。
一番わかりやすかったのが、関数抜けても消されないってこと。
上記の「変数名の前に :: をつける」とか言ってるあたりの処理結果見てると
Test関数内のローカル変数は2回Test関数呼び出しても計算は1から(数値の1じゃなくて最初からって意味)行われているのに対して、グローバル変数は値を保持しているのでTest関数を呼び出すごとに値が増えていっている。
この関数抜けても消されないっていうのが静的変数の特徴。
そもそもローカル変数は関数抜けたら消される。
これは関数が終わる時にデストラクタなるゴジラと戦ってそうな奴が出てきて
関数内のローカル変数をデストロイ、もとい消去してしまうのだそうな。
仮引数に値が渡った時に実引数から仮引数にコピー(初期化)するコンストラクタの裏の顔ですね。
このデストラクタに正面から戦いを挑んで生き残れる強さを持つもののことを静的変数と呼ぶのではないだろうか。(自信ないけどこう覚えることにする)
ってことで static を試してみる。
--------------------------------------------
void Test(){
static int stint = 100;
--stint;
cout << "Test関数内 " << stint << endl;
}
int main(){
Test();
Test();
Test();
Test();
}
(結果)
Test関数内 99
Test関数内 98
Test関数内 97
Test関数内 96
--------------------------------------------
デストロイされてないですね。
関数を抜けても値が保持されているのがわかりますね。
Test関数内では最初に static int stint = 100; と書いてあり宣言と初期化をしていますね。
テキスト読んだら、静的変数の特徴の一つで初期化は1回だけと記載があった。
・・・これポインタでやったり参照でやったりしたらどうなるんだろう。
やってみよう。
static でポインタを作った場合
--------------------------------------------
void Test(){
int i = 100;
static int* stintp = &i;
--*stintp;
cout << "Test関数内 " << *stintp << endl;
}
int main(){
Test();
Test();
Test();
Test();
}
(結果)
Test関数内 99
Test関数内 99
Test関数内 99
Test関数内 99
--------------------------------------------
ダメですね。この場合は static なポインタの持っているアドレスは保持されているはずですが(下記で確認します)、そのアドレスの本家( i )は毎回普通に初期化されているので無意味でした。
本当に static なポインタのアドレスが保持されているか確認↓。
--------------------------------------------
void Test(){
int i = 100;
static int* stintp = &i;
--stintp;
cout << "Test関数内 " << stintp << endl;
}
int main(){
Test();
Test();
Test();
Test();
}
(結果)
Test関数内 0x7fff5fbff708
Test関数内 0x7fff5fbff704
Test関数内 0x7fff5fbff700
Test関数内 0x7fff5fbff6fc
--------------------------------------------
アドレスを減らしていくと関数を抜けてもちゃんと減ったアドレスが保持されていますね。 static なポインタの初期化は確かに一回だけしかしていないのです。
参照はどうでしょうか?
--------------------------------------------
void Test(){
int i = 100;
static int &stintp = i;
--stintp;
cout << "Test関数内 " << stintp << endl;
}
int main(){
Test();
Test();
Test();
Test();
}
(結果)
Test関数内 99
Test関数内 99
Test関数内 99
Test関数内 99
--------------------------------------------
うん、まぁ一緒でしょうね。
ポインタや参照などのアドレスをコピるようなのだとこんな感じ、すごい使い方があるのかもしれないけど初心者な自分には思いつかないな。
とりあえず static は少し理解できた。
ここまで