Daily-C-Studio(12):C語staticキーワード

5021 ワード

Daily-C-Studio(12):C語staticキーワード
堅持することになり,立ち止まることに負ける
キーワードstaticが静かだと勘違いしないでください.実は少しも静かではありません.このキーワードはC言語で主に2つの役割を果たし、C++が拡張した.
一、修飾変数
最初の役割:変数を修飾します.変数はローカル変数とグローバル変数に分けられますが、メモリの静的領域があります.静的グローバル変数、役割ドメインは変数が定義されたファイルに限られ、他のファイルはextern宣言を使用しても使用できません.正確には、役割ドメインは定義された場所から始まり、ファイルの最後に終わり、定義された場所の前のコード行も使用できません.使いたいなら前にextern***を付けなければなりません.気持ち悪いでしょう?気持ち悪くないためには、簡単にファイルの先端で定義すればいいのではないでしょうか.
静的局所変数は、関数体で定義されているもので、この関数でしか使えません.同じドキュメントの他の関数でも使えません.staticで修飾された変数には常にメモリの静的領域が存在するため、この関数の実行が終了してもこの静的変数の値は破棄されず、関数が次回使用されるときにこの値が使用されます.
C/C++では、ローカル変数は格納形式によって3種類のauto,static,registerに分けられ、autoとregisterは前にも述べたように、autoタイプ(普通)のローカル変数と比較してstaticローカル変数はどのような違いがありますか? 
1.記憶領域の割り当てが異なる:autoタイプはスタックに割り当てられ、動的記憶カテゴリに属し、動的記憶領域空間を占め、関数呼び出しが終了すると自動的に解放されるが、staticは静的記憶領域に割り当てられ、プログラムの実行期間全体で解放されない.両者の間の作用域は同じであるが、生存期間は異なる. 
2.staticローカル変数は、モジュールが最初の実行時に初期化作業を行い、一度だけ操作し、もう一度関数に入ったときに初期化文に進んだとき、自動的に初期化されたことをチェックし、初期化プロセスをスキップし、以前に保持していたデータを使用します.
3.ローカル静的変数に対して、初期値を付与しない場合、コンパイル期間は自動的に初期値0または空の文字を付与し、autoタイプの初期値は不確定である.(C++のclassオブジェクト例外の場合、classのオブジェクトインスタンスが初期化されていない場合、staticタイプかどうかにかかわらず、デフォルトのコンストラクション関数が自動的に呼び出されます)
特徴:static局所変数の「記憶性」と生存期間の「グローバル性」
「記憶性」とは、2回の関数呼び出し時に、2回目の呼び出しが入るときに、1回目の呼び出しが終了するときの値を保持できることを意味する. 
#include <iostream>

using namespace std;

void staticLocalVar() 
{ 
	static int a = 0; //          ,       ,          
	cout<<"a="<<a<<endl; 
	++a; 
}

int main() 
{ 
	staticLocalVar(); //      ,   a=0 
	staticLocalVar(); //      ,            ,   a=1 
	return 0; 
}
この例はstaticの記憶性の特徴を説明し、関数呼び出しの回数を記録するとともに、staticの「グローバル性」の特徴を1つの例と説明する.
// IP address to string format 
// Used in Ethernet Frame and IP Header analysis 
const char * IpToStr(UINT32 IpAddr) 
{ 
	static char strBuff[16]; // static    ,          
	const unsigned char *pChIP = (const unsigned char *)&IpAddr; 
	sprintf(strBuff, "%u.%u.%u.%u", pChIP[0], pChIP[1], pChIP[2], pChIP[3]); 
	return strBuff; 
}

通常、ここでstrBuffが正常変数であれば、どのように関数が終了し、strBuff変数のライフサイクルが終了し、メモリが解放されるので、戻ってきたポインタは、再び使用して異常を起こし、ポインタ異常を起こし、ここでstaticを使用すればこの問題をよく解決し、関数は終了するが、strBuff変数は破棄されず、ポインタが指すメモリも回収されず、しかし、ここでは、個人的にはこのような使用をお勧めしません.ここでは、実例分析として、直面した問題を分析します.
現在2つのスレッドAがあると仮定する、Bの実行中にIpToStr()関数を呼び出し、32ビットのIPアドレスをポイント10進数の文字列形式に変換する必要がある.ここで、Aは、まず実行機会を得る、IpToStr()を実行し、入力パラメータは0 x 0 B 090 A 0 Aであり、戻るべきポインタ記憶領域の内容は、"10.10.9.11」は、returnまで実行する場合、実行権を失う、Bスレッドへの実行をスケジューリングし、Bスレッドからの入力パラメータは0 xA 8 A 8 A 8 C 0、静的記憶領域の内容は192.168である.168.168. A実行に再スケジュールすると、strBuffのグローバル一意性のため、コンテンツはBスレッドによって消去され、192.168が戻る.168.168文字列、10.10ではありません.9.11文字列
注意事項:
1.「記憶性」は、プログラムの実行において重要なポイントが再現性であるが、static変数の「記憶性」はこの再現性を破壊し、異なる時刻から実行までの結果が異なる可能性がある.
2.「生存期間」の全局性と唯一性.通常のlocal変数のストレージスペースはstackに割り当てられているため、関数を呼び出すたびに割り当てられたスペースが異なる可能性がありますが、staticはグローバル一意性の特徴を持ち、呼び出すたびに同じメモリを指しているため、重要な問題--再入力不可!!!このようにマルチスレッドプログラム設計や再帰プログラム設計では、この問題に特に注意する.
二、修飾関数の第二の役割:修飾関数.関数にstaticを付けると、関数が静的関数になります.しかし、グローバル変数/関数の役割ドメインを制限するために、関数または変数の前にstaticを加えて、関数を静的関数にします.ただし、ここで「static」の意味は、格納方式ではなく、関数に対する役割ドメインが本ファイルに限られている(したがって内部関数とも呼ばれる)ことを意味する.なお、この場合、外部(グローバル)変数については、staticの制限の有無にかかわらず、その記憶領域は静的記憶領域であり、生存期間はグローバルである.このときのstaticは、役割ドメイン制限の役割を果たすだけで、役割ドメインを本モジュール(ファイル)内部に限定する.
内部関数を使用するメリットは、異なる人が異なる関数を作成するときに、自分で定義した関数が他のファイルの関数と同じ名前になるかどうかを心配する必要がないことです.
//file1.cpp

static int varA; 
int varB; 
extern void funA() 
{ 
	…… 
}

static void funB() 
{ 
	…… 
}

//file2.cpp

extern int varB; //   file1.cpp         
extern int varA; //   ! varA static  ,            
extern vod funA(); //   file1.cpp       
extern void funB(); //   !     file1.cpp   static  

三、静的データメンバー/メンバー関数(C++特有)
C++はこのキーワードを再利用し、前述とは異なる第3の意味を与える:このような特定のオブジェクトに属する変数や関数ではなく、クラスに属することを示す.これは通常のメンバー関数との最大の違いであり、あるクラスのオブジェクトをカウントするときに、何個のクラスを生成するかをカウントするインスタンスなど、静的データメンバーに適用される.ここでstaticは、作用域を限定するものでも生存期間を拡張するものでもない、変数/関数の一意性を示す.これも「クラスに属する、このような特定のオブジェクトに属する変数や関数ではない」という意味である.クラス全体に対して一意であるため、あるインスタンスオブジェクトに属することは不可能である.(静的データメンバーの場合、メンバー関数はstaticかどうかにかかわらず、メモリにコピーが1つしかありません.通常のメンバー関数呼び出しの場合、thisポインタを入力する必要があります.staticメンバー関数呼び出しの場合、thisポインタはありません.)
class EnemyTarget { 
	public: 
		EnemyTarget() { ++numTargets; } 
		EnemyTarget(const EnemyTarget&) { ++numTargets; } 
		~EnemyTarget() { --numTargets; } 
		static size_t numberOfTargets() { return numTargets; } 
		bool destroy(); // returns success of attempt to destroy EnemyTarget object 
	private: 
		static size_t numTargets; // object counter 
}; 
// class statics must be defined outside the class; 
// initialization is to 0 by default 
size_t EnemyTarget::numTargets;

この例では、静的データメンバnumTargetsは、生成するオブジェクトの個数をカウントするためのものである.
また、設計クラスのマルチスレッド操作時には、POSIXライブラリ下のスレッド関数pthread_create()の要求はグローバルであり、通常のメンバー関数は直接スレッド関数とすることができず、Staticメンバー関数をスレッド関数とすることを考慮することができる.
とりあえずここまで、O(∩∩)O~
私のコラムの住所:http://blog.csdn.net/column/details/c-daily-study.html
続きを待つ....