externキーワードの詳細

4226 ワード

基本的な理解
externは変数または関数の前に配置され、変数または関数の定義が別のファイルにあることを示し、コンパイラがこの変数と関数に遭遇したときに他のモジュールで定義を探すようにプロンプトします.
externには2つの役割があります
1.extern"C"void fun(int a,int b);コンパイラはfunという関数名をコンパイルするときにCのルールに従ってC++ではなく対応する関数名を翻訳することを教えて、C++のルールはこの関数名を翻訳する時funという名前を面目が全く異なって、fun@aBc_int_int#%$は、C++が関数のリロードをサポートするため、他の(異なるコンパイラが異なる)場合もあります.(詳細は別のブログに移ります.https://www.cnblogs.com/WindSun/p/11334182.html)

2.ヘッダファイル:extern int g_Int;その役割は、グローバル変数または関数の役割範囲を宣言するキーワードであり、宣言された関数および変数は、このモジュールまたは他のモジュールで使用でき、宣言が定義ではないことを覚えています.つまり、Bモジュールは、Aモジュールで定義されているグローバル変数または関数を参照する場合、Aモジュールのヘッダファイルを含めるだけでよい.コンパイルフェーズでは、モジュールBはその関数または変数が見つからないが、エラーは報告されず、接続時にモジュールAで生成されたターゲットコードからこの関数が見つかる.
externは変数宣言によく用いられる.cファイルにはグローバルな変数が宣言されており、このグローバルな変数が参照される場合は*.hではexternで宣言します.
externの注意事項
(1)extern配列変数
1つのソースファイルに1つの配列が定義されている:char a[6]は、別のファイルで次の文で宣言されている:extern char*aは不可であり、安価で通過できるが、実行時にエラーが発生する.
理由:タイプTを指すポインタはタイプTの配列に等しくない.extern char*aは、文字配列ではなくポインタ変数を宣言するため、実際の定義とは異なり、実行時の不正アクセスをもたらします.宣言はextern char a[]に変更する必要があります.
(2)externグローバル変数
test 1にある場合hヘッダファイルにはグローバル変数の宣言と定義が一緒に配置され、
extern char g_str[] = "123456"; //          extern

二つです.cppファイルにはこれが含まれています.hヘッダファイル、このとき接続test 1をコンパイルする.cppとtest 2.cppの2つのモジュールの場合、接続エラーが報告されます.これは、グローバル変数の定義をヘッダファイルの後に置くためです.test 1.cppこのモジュールにはtest 1が含まれている.hだから一度g_を定義したstr,test 2.cppにはtest 1も含まれている.hだからもう一度g_を定義したstr,このときコネクタはtest 1とtest 2を接続する際に2つのg_を発見するstr.g_をstrの定義はtest 1に置く.h中ならtest 2.cppのコードで#include"test 1.h"を削除変数定義の前にextern:extern char g_を付けるstr[];この時コンパイラはg_を知っていますstrは外部から導入されたコンパイルモジュールであり、このモジュールでもう1つ定義を繰り返すことはありませんが、test 2にはできないため、非常に悪いことです.cppで#include"test 1.h"を使用するとtest 1.hで宣言された他の関数も使用できません.externで修飾しない限り、宣言された関数だけで大きな列が必要になります.だから、ヘッダーファイルで宣言するだけで、真理はいつも簡単であることを覚えておいてください.
义齿
staticのグローバル変数役割ドメインは本ファイルにのみ存在するため、externとstaticは同時に1つの変数を修飾することはできません.externは、この変数が別の場所で定義されていることを示し、ここではその変数を用いる.staticは静的な変数を表し、メモリを割り当てるときは静的領域に格納、スタックには格納されない.externは他のオブジェクトにexternで参照することができるが、staticはできず、オブジェクト自体のみが使用できる.static修飾のグローバル変数宣言は定義と同時に行われます.つまり、ヘッダファイルでstaticを使用してグローバル変数を宣言すると、同時に定義されます.staticがグローバル変数を修飾する役割ドメインは、自身のコンパイルユニットのみである、すなわち、その「グローバル」は、本コンパイルユニットにのみ有効であり、他のユニットには影響しない.
//test1.h:
#ifndef TEST1H
#define TEST1H
static char g_str[] = "123456"; 
void fun1();
#endif

//test1.cpp:
#include "test1.h"
void fun1()  {   cout << g_str << endl;  }

//test2.cpp
#include "test1.h"
void fun2()  {   cout << g_str << endl;  }

以上の2つのコンパイルユニットはtest 1を開くと成功します.objでは、文字列「123456」を見つけることができます.test 2でもいいです.objでそれらを見つけたのは、重複定義のエラーを報告せずに接続に成功したのは、それらが同じ内容を持っているにもかかわらず、記憶されている物理アドレスが異なるためであり、2つの異なる変数が同じ値を付与しているように、この2つの変数がそれぞれのコンパイルユニットに作用しているからである.デバッグ上のコードを追跡すると、2つのコンパイルユニット(test 1,test 2)のg_が見つかります.strのメモリアドレスは同じで、static修飾の変数も他のモジュールに作用することができると結論しましたが、それはあなたのコンパイラがあなたをだましていることを教えてあげます.多くのコンパイラはコードに対して最適化機能を持っていて、生成されたターゲットプログラムがメモリを節約し、実行効率が高く、コンパイラが各コンパイラユニットを接続しているとき、同じ内容のメモリは1部しかコピーされません.例えば、上の「123456」は、2つのコンパイルユニットにある変数が同じ内容である場合、接続時にメモリに1部しか存在しません.上のコードを下のように変更すると、すぐにコンパイラの嘘を解くことができます.
//test1.cpp:
#include "test1.h"
void fun1()
{
    g_str[0] = ''a'';
    cout << g_str << endl;
}

//test2.cpp
#include "test1.h"
void fun2()  {  cout << g_str << endl;  }

void main()     
{
    fun1(); // a23456
    fun2(); // 123456
}

このときコードを追跡すると、2つのコンパイルユニットのg_が見つかります.strアドレスは異なります.1つのモジュールで変更したため、コンパイラはメモリの元の姿を強制的に復元され、メモリには2つのモジュールにコピーされた変数が2つ存在します.staticには以上の特性があるため、staticグローバル変数を定義する際にヘッダファイルではなく元のファイルに配置するのが一般的であり、他のモジュールに不要な情報汚染をもたらすことはありません.
义齿
C++のconst修飾のグローバル定数はstaticと同じ特性を持つため、本コンパイルモジュールでのみ使用できますが、constはexternと接続して、extern const char g_のような他のコンパイルモジュールで使用できる定数を宣言できます.str[]; そして元のファイルで定義を忘れないでください:const char g_str[] = "123456";だからconstが単独で使用するとstaticと同じで、externと一緒に協力すると、その特性はexternと同じです!だからconstについてあまり説明することはありません.私はただあなたに注意したいだけです.const char*g_str="123456"とconst char g_str[]=「123465」は異なり、前のconstではg_ではなくchar*が修飾されています.str、そのg_strは定数ではなく、定義されたグローバル変数(他のコンパイルユニットで使用可能)と見なされているので、char*g_strはconstのグローバル定数のルールを遵守し、const char*const g_をこのように定義することが望ましい.str="123456".