ストレージカテゴリ、リンク、およびメモリ管理
1.ストレージのカテゴリと範囲
C言語には4つのストレージタイプが含まれています。次の表を参照してください。
特徴 | 自動ストレージタイプ | レジスタストレージタイプ | 静的ストレージタイプ | 外部ストレージタイプ |
---|---|---|---|---|
キーワード | 自動 | 登録 | 静的 | 外部 |
に保存 | 羊 | CPUレジスタ | 羊 | 羊 |
デフォルトの初期値 | ジャンク値 | ジャンク値 | 0または空白 | 0または空白 |
範囲 | ブロックに限定 | ブロックに限定 | ブロックに限定 | グローバル |
ライフサイクル | ブロック | ブロック | 機能間に存在する | 機能間に存在する |
ブロックとは、左右の中括弧「{}」で記述されたステートメントのグループを指します。ローカル変数は、ブロックで宣言された変数です。
ローカル変数とグローバル変数の違い:
-
ローカル変数は、ブロックまたは関数内で宣言された変数です。ローカル変数のスコープは、ブロックまたは関数に制限されています。ローカル変数が初期化されていない場合、それらにはガベージデータが含まれます。
-
グローバル変数は、すべてのブロックと関数の前に宣言される変数です。グローバル変数は、その後に宣言されたすべての関数に対して有効です。グローバル変数は、0などのデフォルト値で初期化されます。
範囲
スコープは、識別子にアクセスできるプログラム内の領域を記述します。C変数のスコープは、ブロックスコープ、関数スコープ、関数プロトタイプスコープ、またはファイルスコープです。
-
ブロックスコープ
ブロックは、中括弧で囲まれたコードの領域です。たとえば、関数本体全体がブロックであり、関数内の複合ステートメントもブロックです。ブロックで定義された変数にはブロックスコープがあり、ブロックスコープ変数の表示範囲は、定義から定義を含むブロックの終わりまでです。さらに、関数の仮パラメーターは関数の開始中括弧の前に宣言されますが、それらもブロックスコープを持ち、関数本体のブロックに属します。 -
関数スコープ
関数スコープ(関数スコープ)は、gotoステートメントのタグにのみ使用されます。これは、ラベルが関数の内部ブロックに初めて表示された場合でも、そのスコープが関数全体に及ぶことを意味します。同じラベルが2つのブロックで使用されている場合、混乱を招きます。ラベルの関数スコープにより、これが発生しなくなります。 -
関数プロトタイプスコープ
関数プロトタイプスコープは、以下に示すように、関数プロトタイプのパラメーター名(変数名)に使用されます
。intmighty(int mouse、double large);
関数プロトタイプスコープのスコープは、パラメーター定義の形式からのものです。プロトタイプ宣言の最後で終了します。これは、コンパイラが関数プロトタイプのパラメータのタイプのみを考慮し、パラメータ名(存在する場合)は通常重要ではないことを意味します。さらに、仮パラメーター名がある場合でも、関数定義の仮パラメーター名と一致する必要はありません。可変長配列でのみ、仮パラメーター名が役立ち
ます。voiduse_a_VLA(int n、int m、ar [n] [m]);
関数プロトタイプで宣言された名前は角括弧で囲む必要があります。 -
ファイルスコープ
変数の定義は関数の外にあり、ファイルスコープがあります。ファイルスコープを持つ変数は、その定義から、定義が配置されているファイルの終わりまで表示されます。
2.リンク
C変数には、外部リンク、内部リンク、またはリンクなしの3つのリンク属性があります。
ブロックスコープ、関数スコープ、または関数プロトタイプスコープを持つ変数は、リンクされていない変数です。これは、これらの変数が、それらが定義されているブロック、関数、またはプロトタイプに対してプライベートであることを意味します。ファイルスコープを持つ変数は、外部リンクまたは内部リンクにすることができます。外部リンク変数はマルチファイルプログラムで使用でき、内部リンク変数は1つの変換ユニットでのみ使用できます。
詳細リンク
3.保管期間
スコープとリンクは、識別子の可視性を説明します。保存期間は、これらの識別子を介してアクセスされるオブジェクトの存続期間を表します。
Cオブジェクトには、静的ストレージ期間、スレッドストレージ期間、自動ストレージ期間、および動的割り当てストレージ期間の4つのストレージ期間があります。
オブジェクトに静的な保存期間がある場合、プログラムの実行中は常に存在します。ファイルスコープ変数には静的ストレージ期間があります。ファイルスコープ変数の場合、キーワードstaticは、保存期間ではなく、リンク属性を示すことに注意してください。静的として宣言されたファイルスコープ変数には内部リンケージがあります。ただし、内部リンクであろうと外部リンクであろうと、すべてのファイルスコープ変数には静的ストレージ期間があります。
スレッドストレージ期間は並行プログラミングに使用され、プログラムの実行は複数のスレッドに分割できます。スレッドストレージ期間のあるオブジェクトは、宣言されてからスレッドの終わりまで存在します。オブジェクトがキーワード_Thread_localで宣言されると、各スレッドは変数のプライベートコピーを取得します。
ブロックスコープの変数には通常、自動保存期間があります。プログラムがこれらの変数が定義されているブロックに入ると、これらの変数にメモリが割り当てられます。ブロックが終了すると、変数に割り当てられたばかりのメモリが解放されます。このアプローチは、自動変数によって占有されているメモリを再利用可能な作業領域または一時記憶領域として扱うことと同等です。たとえば、関数呼び出しが終了した後、その変数によって占有されているメモリを使用して、次に呼び出される関数の変数を格納できます。可変長配列はわずかに異なり、それらの保存期間は、ブロックの最初から最後までではなく、宣言からブロックの最後までです。
4.独立した動的変数
自動ストレージカテゴリに属する変数には、自動ストレージ期間、ブロックスコープがあり、リンクはありません。デフォルトでは、ブロックまたは関数ヘッダーで宣言された変数はすべて、自動ストレージカテゴリに属します。
自動保存期間のある変数は、プログラムが変数が宣言されているブロックに入ると変数が存在し、プログラムがブロックを出ると変数が消えることを意味します。変数が元々占有していたメモリ位置を他の目的に使用できるようになりました。
静的変数 | 自動変数 | レジスタ変数 |
---|---|---|
コードブロック外で宣言されたすべての変数 | コードブロック内で定義された変数 | レジスタで変更された変数 |
静的メモリに保存 | ヒープとスタックに格納されます | レジスターに保管 |
プログラムの実行前に作成され、プログラムの終了までの実行全体にわたって存在します | 制御フローは、コードブロックに入るときに作成され、出るときに破棄されます | 作成と破棄の時間は自動変数と同じです |
5.ブロックスコープの静的変数
静的変数は不変の変数のように聞こえます。実際、静的とは、変数の値が変更されないことではなく、変数がメモリ内の所定の位置にとどまることを意味します。
ファイルスコープを持つ変数は、自動的に静的ストレージ期間を持ちます(そしてそうである必要があります)。
静的ストレージ期間とブロックスコープを使用してローカル変数を作成できます。これらの変数のスコープは自動変数と同じですが、プログラムがそれらの変数が配置されている関数を離れた後、これらの変数が消えることはありません。つまり、この変数にはブロックスコープがあり、リンクはありませんが、静的ストレージ期間があります。コンピューターは、複数の関数呼び出しの間でそれらの値を記録します。ブロック内(ブロックスコープを指定し、リンクを指定しない)で、この種の変数をストレージクラス指定子static(静的ストレージ期間を指定)で宣言します。
6.外部リンクの静的変数
外部にリンクされた静的変数には、ファイルスコープ、外部リンク、および静的ストレージ期間があります。このカテゴリは外部ストレージクラスと呼ばれることもあり、このカテゴリに属する変数は外部変数と呼ばれます。変数の定義宣言をすべての関数の外に置くと、外部変数が作成されます。もちろん、関数が外部変数を使用していることを指摘するために、キーワードexternを使用して、関数で再度宣言することができます。ソースコードファイルで使用される外部変数が別のソースコードファイルで定義されている場合は、externを使用してそのファイルで変数を宣言する必要があります。
次のように:
int Errupt; /* 外部定义的变量 */
double Up[100]; /* 外部定义的数组 */
extern char Coal; /* 如果Coal被定义在另一个文件,则必须这样声明 */
void next(void);
int main(void)
{
extern int Errupt; /* 可选的声明*/
extern double Up[]; /* 可选的声明*/
...
}
void next(void)
{
...
}
main()でUp配列を宣言する場合(これはオプションの宣言です)、最初の宣言で配列サイズ情報が既に提供されているため、配列サイズを指定する必要がないことに注意してください。main()の2つのextern宣言は完全に省略できます。これは、外部変数にファイルスコープがあるため、宣言からファイルの終わりまでErruptとUpが表示されるためです。これらは、main()関数がこれらの2つの変数を使用することを示すためにのみ表示されます。
7.ランダム機能
ヘッダーファイルを含める必要があります:
#include <stdlib.h>
rand()関数は指定された順序で整数を生成するため、上記のステートメントが実行されるたびに、同じ2つの値が出力されます。したがって、C言語のランダム性は、本当の意味でランダムではありません。疑似乱数と呼ばれます。rand()を使用して乱数を生成する前に、ランダムジェネレーター(これもstdlib.hにあります)の初期化関数srand(unsigned seed)を使用して疑似乱数シーケンスを初期化する必要があります。シードはランダムシードとも呼ばれます。素人の用語では、毎回提供する場合シードが同じである場合、各ラウンドで生成される最後のいくつかのランダム値も同じであるため、疑似乱数と呼ばれるため、必要です完全なランダム性を実現するために、毎回異なるシードを提供します。通常、時間関数time(NULL)をシードとして使用します。時間値は毎秒異なるため、この関数には次のヘッダーファイルを含める必要があります。
#include <time.h>
8.メモリの割り当て:malloc()およびfree()
上司が言ったことを見てください:
9. ANSIC型修飾子
1.const型修飾子
説明 | 例 | 意味 |
---|---|---|
タイプ前の定数 | const float * p | ポインタ自体は変更可能であり、指定された値は変更できません |
変数名の前の定数 | float * const p | ポインタ自体は変更できず、ポイント値も変更できます |
タイプ、変数名の前のconst | const float * const p | ポインタ自体は変更できません。また、指定された値は変更できません。 |
タイプの後、* constの前 | float const * p | ポインタ自体は変更可能であり、指定された値は変更できません |
一般的に:constは[]の左側に配置され、ポインターが指すデータは変更できません。[]の右側に配置され、ポインター自体は変更できません。
2.揮発性型修飾子
揮発性修飾子は、エージェント(変数が配置されているプログラムではない)が変数の値を変更できることをコンピューターに通知します。通常、ハードウェアアドレスに使用され、同時に実行されている他のプログラムまたはスレッド間でデータを共有します。
(1)コンパイラーは、揮発性の変更された変数の読み取りおよび書き込みの最適化を禁止します。
volatileキーワードは型修飾子です。これで宣言された型変数は、オペレーティングシステム、ハードウェア、その他のスレッドなど、コンパイラーが知らないいくつかの要因によって変更される可能性があります。このキーワードで宣言された変数に遭遇すると、コンパイラーは、特別なアドレスへの安定したアクセスを提供するために、変数にアクセスするコードを最適化しなくなります。
(2)揮発性の変更された変数が読み取られるたびに、メモリから読み取られます。
揮発性は「元のメモリアドレスへの直接アクセス」と解釈できます。「変動性」は、マルチスレッド、割り込みなどの外部要因によって引き起こされます。揮発性で変更された変数が「揮発性」であるためではなく、外部の原因ではありません。揮発性の定義を使用しても、変更されません。
3.型修飾子を制限する
制限キーワードを使用すると、コンパイラーはコードの特定の部分を最適化して、計算をより適切にサポートできます。これはポインターにのみ使用でき、ポインターがデータオブジェクトにアクセスする唯一の最初の方法であることを示します。
Restrictは、C99標準で導入されました。これは、ポインターを制限および制限するためにのみ使用できます。オブジェクトはポインターによって参照されており、オブジェクトのコンテンツは、ポインターを除く他のすべての直接または間接メソッドによって変更できません。つまり、ポインタが指すメモリの内容を変更するすべての操作はポインタを介して変更する必要があり、他の手段(他の変数またはポインタ)では変更できないことをコンパイラに通知します。これの利点は、コンパイラがより効率的なアセンブリコードを生成するために、より最適化されたコードを実行するのに役立ちます。たとえば、int * limit ptrが指すメモリユニット、ptrはptrのみがアクセスでき、このメモリユニットを指す他のポインタは次のとおりです。未定義、わかりやすい無効なポインタです。制限の出現は、C言語に固有の欠陥によるものです。Cプログラマーはこの欠陥を積極的に回避する必要があり、コンパイラーも非常に協力してコードを最適化します。
制限修飾子は、関数パラメーターのポインターにも使用できます。つまり、コンパイラーは、関数本体の他のIDがポインターが指すデータを変更しないと想定でき、コンパイラーは、他の目的に使用されないようにデータを最適化しようとすることができます。