目次
多くの若いプログラマーは、C 言語を学習する後期段階でよくこの疑問を頭の中に抱くと思います。「私が定義したデータはどのようにしてメモリに保存されるのでしょう?」
今日は、データがメモリにどのように保存されるかについて詳しく説明します。
データがどのようにメモリに保存されているかを知るには、まずどのようなデータがあるかを知る必要があります。タイプ
1. データ型の基本的な分類
1. 形成外科ファミリー
char
signed char
unsigned char
short
signed short< /span> 符号付きlong long 符号なし、long、long long long 符号なしlong 符号付きlong long unsigned int signed int int
unsigned short
注: char 型のデータは ACEII コード値としてメモリに格納されるため、char は整数ファミリーに属すると考えられます。
2. 浮動小数点ファミリー
浮動小数点数
倍精度浮動小数点数
3.ポインタ型
int *p;
char *p;
float *p;
ボイド *p;
4.空型
空所
注: 空の型は通常、関数の戻り値、ポインター型、および関数パラメーターに使用されます。
5.工事の種類
int [10] 配列型(変数名を除いた型) 例: int a [5] の型は int [5]
struct 構造体の種類
enum 列挙型
ウミオンユニオンタイプ
类型的意义:
1. メモリ内でこのタイプの変数が占めるスペースのサイズを決定します。
2. どのような視点で見るべきですか?
この知識を踏まえて、本題に取り掛かりましょう。小さなプログラマーの皆さん、必ず読んでください。次のステップは重要なポイントです。 ! !
2. メモリ空間へのプラスチック形状の保存
1. 原コード、逆コード、補コード
まず次のことを知る必要があります:元のコード、逆コード、補完コード
元のコード: 整数をバイナリ形式で直接表現します
1 の補数コード: 符号ビットを除き、元のコードの他のビットをビットごとに反転して 1 の補数コードを取得します
補数コード: 補数コードに 1 を加算して補数コードを取得します
注意してください:
1. 元のコード、補数コード、正の数の補数コードは同じです。
2. 元のコード、補数コード、負数の補数コードは上記の規則に従います。
例えば
int a = -1;
原码:10000000000000000000000000000001
反码:1111111111111111111111111111111111110
花码:111111111111111111111111111111111111
元のコードを逆コードに変換しても、符号ビットは変更されません。 ! !
int a = 1;
原码:00000000000000000000000000000001
反码:00000000000000000000000000000001
花码:000000000000000000000000000000001
注: 補数コードの形式でメモリに保存されます。
この時点で、多くの小規模なプログラマーは次のような疑問を持つかもしれません。元のコードは未使用のままにしておくだけなのに、なぜそれを保存するために補完コードを使用する必要があるのでしょうか?ただ一つ言えるのは、あなたはまだ若すぎるということです
簡単な例として、元のコードにデータ型を格納すると仮定します。
int a = 1;
原码:00000000000000000000000000000001
int b = -1;
原码:10000000000000000000000000000001
int c =a+b;
00000000000000000000000000000001
10000000000000000000000000000001
10000000000000000000000000000010
元のコードを使用してメモリにデータを保存すると、ここでの a+b の値は 2 であることがわかります。数学的な観点から見ると、1+-1 は 0 に等しいはずですよね?
したがって、科学者はデータ型を 2 の補数形式でメモリに格納する方法を考え出しました。
int a = -1;
原码:10000000000000000000000000000001
反码:1111111111111111111111111111111111110
花码:111111111111111111111111111111111111
元のコードを逆コードに変換しても、符号ビットは変更されません。 ! !
int a = 1;
原码:00000000000000000000000000000001
反码:00000000000000000000000000000001
花码:000000000000000000000000000000001
a + b
(ここの 1 は保存できないため破棄されます)
(1)00000000000000000000000000000000
花码:00000000000000000000000000000000
反码:00000000000000000000000000000000
原码:00000000000000000000000000000000
このため、2 の補数の形式でメモリに保存されます。
2. データの値の範囲
データには保存範囲があることは誰もが知っていますが、この範囲はどれくらいなのでしょうか?次にchar型データを例に挙げます。
次のように、char 型は 8 ビット サイズの 1 バイトを格納できることがわかっています。
注: 以下はメモリ内の格納状況です。これは、この時点でデータの補数が格納されていることを意味します。 ! !
00000000 0
00000001 1
00000010 2
……
011111110 126
011111111 127
10000000 -128 注: 10000000 がメモリ内で認識されると、-128 として直接解析されます
10000001 -127
……
111111110 -2
111111111 -1
char型データが格納できる値は-128~127であることがわかります
ここから推論を導き出し、int short などの値の範囲を推定できます。整数ファミリー
3.ビッグエンディアンとリトルエンディアンとは何ですか?
ビッグ エンディアン: データの上位エンディアン順序を下位アドレスに格納し、データの下位エンディアン順序を上位アドレスに格納します。
リトル エンディアン: データの上位エンディアン順序を上位アドレスに格納し、データの下位エンディアン順序を下位アドレスに格納します。
注: ここで何が起こっているのか理解できなくても問題ありません。詳細な説明は以下にあります。
まず、vs でデバッグし、データがどのように保存されるかを観察します。
int a =1;
原码:00000000000000000000000000000001
反码:00000000000000000000000000000001
花码:000000000000000000000000000000001
注: メモリに保存されているものはバイナリ表現であり、よりよく観察するために vs は 16 進数形式で示しています。
16 進数表現に変換する
0x00000001
論理的に言えば、メモリに保存すべきものは 00 00 00 01 です。なぜここで 01 00 00 00 なのでしょうか?
実際、正確に取り出すことができれば、メモリにどのように保存しても問題ありません。
ここでは便宜上、0x11 22 33 44 を例として使用します
注:左側を下位アドレス、右側を上位アドレスとする(以下同様)
1. 11 22 33 44
2. 44 33 22 11
3. 11 22 44 33
4. 11 33 22 44
...
後で書く方法はたくさんあります
削除して選択した後も、比較的簡単で残されている書き込み方法が 2 つあります。
最初のタイプ: 11 22 33 44 (これはビッグ エンディアンストレージと呼ばれます)
2 番目のタイプ: 44 33 22 11 (これはリトル エンディアンストレージと呼ばれます)
さて、次の文はよく理解できると思います
ビッグ エンディアン: データの上位エンディアン順序を下位アドレスに格納し、データの下位エンディアン順序を上位アドレスに格納します。
リトル エンディアン: データの上位エンディアン順序を上位アドレスに格納し、データの下位エンディアン順序を下位アドレスに格納します。
次に、現在のコンピュータにビッグ エンディアン ストレージがあるかリトル エンディアン ストレージがあるかを判断するコードを作成します (注: コンピュータにビッグ エンディアン ストレージがあるかリトル エンディアン ストレージがあるかエンディアン ストレージは購入するかどうかによって異なります。エンディアンはコンピュータによって決定され、使用するコンパイラとは関係ありません)
考え方: ビッグ エンディアン ストレージの場合、データ 1 の下位アドレスは 0 として格納され、リトル エンディアン ストレージの場合、データ 1 の下位アドレスは 1 として格納されます。整数変数 int a = 1 を定義し、それを格納するには char * 型のポインタを使用しますが、このとき格納されるのは a のローエンディアン順のバイトです。
int check_sys()
{
int i = 1;
return (*(char*)&i);
}
int main()
{
int ret = check_sys();
if (ret == 0)
{
printf("大端");
}
else if (ret == 1)
{
printf("小端");
}
return 0;
}
私のコンピュータでは、リトル エンディアン ストレージですが、私の考えに従って、自分のコンピュータがビッグ エンディアン ストレージとリトル エンディアン ストレージのどちらを実装しているかを確認することもできます。
これを読むとデータについての理解がさらに深まると思いますので、この章はここまでとします。プログラマーの皆さん、また次の記事でお会いしましょう。