内なる力を養う [メモリ内のデータ保存の詳細な分析]

メモリ内のデータストレージ

形成外科

始める前に、元のコードの逆コードと補完コードとは何か、という予備知識を持ってみましょう。

オリジナルコード

元のコードは、値を正と負の数の形式のバイナリに直接変換することで取得できます。

逆コード

元のコードの符号ビットを変更しないで、他のビットを順番に反転して、逆コードを取得します。

補体

逆コード + 1 は補数コードを取得します。


上記の予見により、コンピューターのメモリ内の次のステップに進むことができます。

コンピュータにおける整数のバイナリ表現方法には、原符号、補符号、補符号の 3 種類があります。
3 つの表現方法にはいずれも、符号ビットと値ビットの 2 つの部分があり、符号ビットは「正」を表すために 0 を使用し、「負」を表すために 1 を使用します

負の整数を表す方法は 3 つあります。

整数のメモリに格納される 2 進数は2 の補数ですが、なぜ 2 の補数なのでしょうか?

コンピュータ システムでは、値は常に 2 の補数で表現され、格納されます。その理由は、補数コードを使用すると、符号ビットと値フィールドを
均一に処理できると
同時に、加算と減算も均一に処理できるためです(CPU には加算器しかありません)。元のコードと相互に変換され、動作プロセスは
同じであり、追加のハードウェア回路は必要ありません。

1-1
1+-1//因为CPU只有加法器
00000000000000000000000000000001//1的原码
10000000000000000000000000000001//-1的原码
11111111111111111111111111111110//-1的反码
11111111111111111111111111111111//-1的补码
00000000000000000000000000000001//相加
100000000000000000000000000000000//进1,截断多余的部分,即为0

オリジナルコードを利用してオリジナルコードを追加する場合

00000000000000000000000000000001//1的原码
10000000000000000000000000000001//-1的原码
10000000000000000000000000000010//结果为-2

上の例から、メモリ内での計算に2 の補数コードが使用されていることが明確にわかります。

ここに画像の説明を挿入

正の数の元の否定は同じであり、0x は 16 進表現を表します

-1 はすべて 1 を格納し、16 進表現では ff ff ff ff が表示されます。

-1 はすべて 1 を格納し、16 進数表現では ff ff ff ff を示します。

しかし、不審な現象が見つかりました。
なぜストレージが逆になっているのでしょうか?
これは、ビッグエンディアンとスモールエンディアンが何であるかを言う必要があります

:ビッグ エンディアン (ストレージ) モードは、データの下位ビットがメモリの上位アドレスに格納され、データの上位ビットがメモリの低位アドレスに格納されることを意味します。リトル エンディアン (ストレージ) モードは、
データの下位ビットがメモリの上位アドレスに格納されることを意味します。データのビットはメモリの下位アドレスに格納され、データの上位ビットはメモリの上位アドレスに格納されます。


ここに画像の説明を挿入
上記のような図

次のステップは、
Baidu の面接の質問である時間内に統合することです。

ビッグエンディアンとリトルエンディアンの概念を簡単に説明し、現在のマシンのバイト順序を決定する小さなプログラムを設計してください。

概念についてはすでに説明しましたので、
実際の操作に直接進みましょう

int check_sys()
{
    
    
     int i = 1;
     char* p=(char*)&i;
     return *p;
}
int main()
{
    
    
      int ret = check_sys();
      if(ret == 1)
     {
    
    
       printf("小端\n");
     }
      else
     {
    
    
      printf("大端\n");
     }
 return 0;
 }

トピックトレーニング

トレーニング効果を高めるため、少し質問数が増えています
質問1

1. 出力は何ですか?
#include <stdio.h>
int main()
{ char a= -1; signed char b=-1; unsigned char c=-1; printf("a=%d,b=%d,c=%d" 、a、b、c); 0 を返します; }





-1是整数
11111111111111111111111111111111//补码
//因char只能存放8字节,故阶段多余的
11111111//a中实际存放的
//注意:%d是10进制形式,打印有符号
//     %u是10进制形式,打印无符号
//则a先整形提升
11111111111111111111111111111111
10000000000000000000000000000001//转换成原码为-1,打印的即为-1
//signed char同理
//对于unsigned char -1在c中实际存放的也是
11111111
00000000000000000000000011111111//整形提升(无符号提升0)
//故打印的为255

質問2

#include <stdio.h>
int main()
{ char a = -128; printf(“%u\n”,a); 0を返します。}



10000000000000000000000010000000//原码
11111111111111111111111101111111//反码
11111111111111111111111110000000//补码
10000000//a中实际存储
11111111111111111111111110000000//整形提升
//因为以%u的形式打印,每位都是有效位
结果为4294967168

質問3

int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
//2 の補数の形式で演算し、最終的に符号付き整数にフォーマットします

11111111111111111111111111101100//i补码
00000000000000000000000000001010//j补码
11111111111111111111111111110110//结果的补码
10000000000000000000000000001010//结果的圆码
故结果为-10

質問4

unsigned int i;
for(i = 9; i >= 0; i–)
{ printf(“%u\n”,i); }

そうです、トピックが簡潔であればあるほど、落とし穴は大きくなります。
正でも負でも符号なしは正であることを知っておく必要があり、答えが無限ループであることは
明らかです。

質問5

int main()
{ char a[1000]; int i; for(i=0; i<1000; i++) { a[i] = -1-i; printf (“%d”,strlen(a)); 0を返します。}








ここに画像の説明を挿入
このパイを読んだ後、自分は賢いと信じてください、あなたはひらめきを持っているに違いありません

浮動小数点

最後にお待ちしています~~
まず、紹介

int main()
{
    
    
 int n = 9;
 float *pFloat = (float *)&n;
 printf("n的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 *pFloat = 9.0;
 printf("num的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 return 0;
}

考えて
答えを出してください。1
と4は皆さん問題ないと思いますが、
ここに画像の説明を挿入
なぜこのようなことが起こるのでしょうか?格納方法
が異なるため、単純な元の逆補符号ではありません。なぜそうでないのかというと、見てください~~

国際標準 IEEE (電気電子工学研究所) 754 によれば、任意の 2 進浮動小数点数 V は次の形式で表現できます

1・(-1)^S * M * 2^E
2・(-1)^S は符号ビットを表し、S=0 の場合、V は正の数、S=1 の場合、V は負の数になります。
M は、1 以上 2 未満の有効な数値を表します。
3・2^Eは指数を表します。

読んで混乱すると思いますが、10進法について
簡単に説明すると、5.5を2進法に変換したものです 2進: 101.1はIEEE規格で書くと1.011*2^2 (-1)^0 ×1.011 × 2^2 to get S=0; M=1.011; //常に1.E=2の形式に変換できます;その後、次の方法で保存します。32 ビット浮動小数点数の場合、最大値は 1 bit は符号 Bit s、次の 8 ビットは指数 E、残りの 23 ビットは仮数 M です。64 ビット浮動小数点数の場合、最上位ビットは符号ビット S、次の 11 ビットは指数 E、残りの 52 ビットは仮数 M です。



ここに画像の説明を挿入








ここに画像の説明を挿入

ここに画像の説明を挿入

置くだけ収納です、のののん〜M

前述したように、1≤M<2、つまり M は 1.xxxxxx の形式で記述できます。xxxxxx は小数部を表します。
IEEE 754 では、M をコンピュータ内に保存する場合、デフォルトではこの数値の最初の 1 桁が常に 1 であるため、これを破棄して、次の xxxxxx 部分のみを保存することが規定されています
たとえば、 1.01 を保存する場合は
、01 のみを保存し、読み取り時に最初の 1 を追加します。これを行う目的は、有効数字 1 桁を節約することです。32 ビット
浮動小数点数を例にとると、M には 23 ビットだけが残ります。
最初の 1 が破棄されると、24 個の有効数字を保存できます。

Eに関しては、少し複雑で抽象的です (問題を理解しているかどうかは問題ではありません。結局のところ、この問題は古代のボスの表で議論されました)

まず、E は符号なし整数 (unsigned int) であり
、E が 8 ビットの場合、その値の範囲は 0 255 であり、E が 11 ビットの場合、その値の範囲は 0 2047 であることを意味します。ただし、科学表記法の Eには負の数が含まれる可能性があることがわかっているため、IEEE 754 では、メモリに格納するときに E の実数値に中間数を加算する必要があると規定しています。8 ビット E の場合、この中間数は 127 、11 の
場合は-ビット E、この中間数値は 1023 です。たとえば、2^10 の E は 10 であるため、32 ビット浮動小数点数として保存する場合は、10+127=137 (つまり 10001001) として保存する必要があります



入れて理解したら、次のステップはそれを取り出す方法です

E はすべて 0 またはすべて 1 ではありません(通常)

このとき、浮動小数点数は次の規則で表されます。つまり、指数 E の計算値から 127 (または 1023) を引いて実数値を求め、その前に最初の桁の 1 を追加します
。有効数M。
例:
0.5 (1/2) の 2 進数形式は 0.1 です。正の部分は 1 でなければならないため、つまり小数点が 1 ビット右にシフトされるため、1.0*2^(-1) となります
。 、その順序コードは -1+127= 126 で、
01111110 と表現されます。仮数 1.0 は整数部分を削除して 0 にし、0 ~ 23 桁の 000000000000000000000000 を埋めます。そのバイナリ
表現は次のようになります。

0 01111110 00000000000000000000000

Eはすべて0です

このとき、1 ~ 127 (または 1 ~ 1023) に等しい浮動小数点数の指数 E が実数値となり、有効数
M は最初の 1 桁の 1 と加算されなくなり、元の数値に戻ります。 10 進数の 0.xxxxxx。これは、±0、および
0 に近い非常に小さな数値を表すために行われます。

Eはすべて1です

このとき、有効数Mがすべて0であれば±無限大を意味します(正負は符号ビットsにより異なります)

これで冒頭の引用が説明できるようになります
ここに画像の説明を挿入

n中存储9
0 00000000 00000000000000000001001//正数原码即补码
&n之后强转为float*类型
以浮点型的形式打印,对照下表
则S放0,E为00000000,M为00000000000000000001001
按照(-1)^S * M * 2^E形式写出
(-1^0× 0.00000000000000000001001×2^-126
显然,V是一个很小的接近于0的正数,所以用十进制小数表示就是0.000000

ここに画像の説明を挿入

*pFolat赋值为9.0,也就是以浮点数的形式存储
9.0的二进制
1001.0
即(-1^0×00100000×2^3
 s=0, M=1.001,E=3+127=130
 放入内存中
 0 10000010 00100000000000000000000%d的形式打印
 正是 1091567616

追加歓迎

おすすめ

転載: blog.csdn.net/2301_78636079/article/details/132113486