C言語の記憶類説明子

8291 ワード

役割ドメインリンク属性格納時期格納タイプ内容はまずブログを参照してください
C言語には5種類の修飾子が格納されている:auto register static extern typedef以下に各説明子の使い方を紹介する.
  • auto:変数が自動記憶タイプautoを有することを示す説明子は、コードブロックの役割ドメインを有する変数の宣言にのみ使用できるが、これらの変数自体が自動記憶タイプ(ランタイムスタックに格納)を有するため、autoは通常、明示的な説明の役割を果たすだけである.
  • register:変数がハードウェアレジスタを有することを示す格納タイプregisterも、コードブロックの役割ドメインを有する変数の宣言にのみ用いることができ、プログラマがCPUのレジスタにこの変数を置くことを望んでいることを示し、通常の変数よりも早く変数にアクセスして操作することができる.ただし、レジスタの格納タイプの変数のアドレスを取得することができず、registerが宣言する変数をレジスタに格納するか否かはコンパイラによって決定される.
  • static:変数が静的ストレージタイプを有するか、識別子が内部リンク属性を有することを示す
  • staticコードブロックの役割ドメインを有する変数の宣言に用いる場合には、その変数に静的記憶タイプ(静的メモリに格納)を持たせる.
  • staticは、ファイルの役割ドメインを有する識別子(変数名、関数名)に用いる場合、その識別子が内部リンク属性を有することを示す.

  • extern:識別子が外部リンク属性を有することを示すか、またはその変数がexternの使用を理解するために他の場所で定義されていることを示す.まずC言語の宣言と定義の違いを理解する.宣言:記述プログラムの他の場所で定義されたオブジェクト定義:オブジェクトにメモリを割り当てる
  • .
    次の文がすべての関数体の外に表示されている場合
  • int i;はint型変数を定義し、メモリを割り当て、デフォルトの初期化を0
  • に実行する.
  • int i = 1;はint型変数を定義し、メモリを割り当て、1
  • に初期化する.
  • extern int i = 1;はint型変数を定義し、メモリを割り当て、1に初期化する.識別子iはファイルの役割ドメインを有するため、デフォルトでは外部リンク属性を有するが、externの役割は明示的な説明識別子iが外部リンク属性
  • を有するだけである.
  • extern int i;は変数iがint型であることを記述し、プログラムの他の場所で定義(メモリの割り当て)され、ここで他の場所は現在のコンパイルユニット(同じソースファイル)または他のコンパイルユニット(他のソースファイル)を含む.zはextern宣言と呼ぶことができ、外部リンク属性を有する識別子は複数のソースファイルで使用することができ、同じエンティティ
  • を指す.
    // main.c
    #include 
    extern int i; // i extern 
    int main(void)
    {
        int i = 1; // i 
        printf("%d", i);
        return 0;
    }
    // main.c
    #include 
    extern int i; // i extern 
    int main(void)
    {
        printf("%d", i);
        return 0;
    }
    // define.c
    int i = 1; // i 
    

    次の文が関数内に表示されている場合
  • int i;はint型変数を定義し、メモリを割り当てるが、初期化は実行されず、iの値はランダムであり、この変数に不正な
  • にアクセスする.
  • int i = 1;はint型変数を定義し、メモリを割り当て、1
  • に初期化する.
  • extern int i = 1;この文は、同様にint変数iを定義しようとする、識別子iを外部リンク属性に設定しようとするが、C言語では関数内部で外部変数を初期化できないことが規定するため、この文は不正である.では、関数の外部で文int i = 0を使用して定義して初期化し、extern int i = 1を付与操作と見なしますか?関数外部のint i = 0はiの定義であるため、関数内部のextern int i = 1もiの定義であり、これによりiの繰返し定義エラー
  • が生じる.
  • extern int i;この文は関数体の内部に置くと複雑で、いくつかの例を挙げる.
  • // program 1
    // main.c
    #include 
    int main(void)
    {
        extern int i;
        return 0;
    }

    プログラム1コンパイルパス..
    // program 2
    // main.c
    #include 
    int main(void)
    {
        extern int i;
        printf("%d", i);
        return 0;
    }

    プログラム2はwin 7+VS 2015プラットフォームの下でエラーを報告します:error LNK 2001:解析できない外部記号_i
    // program 3
    // main.c
    #include 
    int main(void)
    {
        printf("%d", i);
        return 0;
    }

    プログラム3はwin 7+VS 2015プラットフォームの下でエラーを報告します:error C 2065:“i”:宣言されていない識別子
    // program 4
    // main.c
    #include 
    int i = 1;
    int main(void)
    {
        extern int i;
        printf("%d", i);
        return 0;
    }

    プログラム4のコンパイルに成功し、1を印刷した.
    // program 5
    // main.c
    #include 
    int main(void)
    {
        int i = 1;
        extern int i;
        return 0;
    }

    プログラム5 win 7+VS 2015でerror C 2086:“int i”:再定義
    // program 6
    // main.c
    #include 
    int main(void)
    {
        extern int i;
        int i = 1;
        return 0;
    }

    プログラム6 win 7+VS 2015でerror C 2086:“int i”:再定義
    // program 7
    // main.c
    #include 
    int main(void)
    {
        extern int i;
        printf("%d", i);
        return 0;
    }
    // define.c
    int i = 1;

    プログラム7のコンパイルにより、1を印刷する.
    上記の例を総合すると、コンパイラ時にまずiが定義されているか否か(メモリが存在する)を判断し、定義されていない場合はextern int i;をiに対するextern宣言とする.iの定義がある場合はiのリンク性を判断し、外部リンクであればextern int i;をiのextern宣言とし、iが無リンク属性であればextern int iをiに対する定義とし、externを用いるiを外部リンク属性と強制する(初期値が付与されていないため関数内部で外部変数を初期化できないエラーは発生しない)、これにより2つのiの定義があるため、エラーを報告して繰り返し定義する.
    以上externの使い方については個人的な推測にすぎません
  • typedef typedef説明子は、オブジェクトのために記憶空間を予約することはなく、それを記憶クラス説明子に分類するのは、文法記述の便利さのためである.

  • ストレージ・クラス・ディスクリプタについては、次の点を説明します.
  • 宣言には、最大1つのストレージクラス説明子
  • しかありません.
  • クラス説明子が識別子を変更できない役割ドメイン
  • を格納する.
  • staticは、記憶タイプを変更するためにもリンク属性を変更するためにも使用することができ、具体的にどのような役割を果たすかは、その修飾識別子の役割ドメインによって決定される
  • である.
  • は、externによって修飾する識別子が外部リンク属性を有する場合にのみextern宣言
  • として扱われる.
  • register修飾変数は実際にレジスタに格納かどうかコンパイラ決定
  • がある.