深度剖析資料在記憶體中的存盤
- 一、資料型別詳細介紹
- 1.資料型別介紹
- 2.型別的基本歸類
- 二、整形在記憶體中的存盤
- 1.借用除錯觀察
- 2.大小端位元組序
- 3.整形在記憶體中的存盤:原碼、反碼、補碼
- 3.1原碼、反碼、補碼
- 3.2補碼的意義
- 三、浮點型在記憶體中的存盤決議
- 1.浮點型資料的存盤規則
- 2.浮點數的精度損失
一、資料型別詳細介紹
這里我們僅介紹基本資料型別在記憶體中的存盤方式、規則,
1.資料型別介紹
char //字符資料型別
short //短整型
int //整形
long //長整型
long long //更長的整形
float //單精度浮點數
double //雙精度浮點數
注意:C語言中沒有字串型別,我們常用陣列來儲存字串,
2.型別的基本歸類

二、整形在記憶體中的存盤
1.借用除錯觀察
我們知道一個變數的創建是要在記憶體中開辟空間的,空間的大小是根據不同的型別決定的,
接下來我們以32位作業系統為設定,來探討資料在記憶體中的存盤,
我們定義一個int 型數字:
#include<stdio.h>
#include<stdlib.h>
int main(){
int num = 10;
system("pause");
return 0;
}
我們定義了一個變數,接下來我們用除錯視窗來訪問這個變數在記憶體中的存在形式:
啟動除錯->除錯->視窗->記憶體
接下來我們會看到這樣一個表格:
我們可以在記憶體中直接取地址來找變數:
輸入&num
我來仔細梳理一下這個表格的意思:
因為num是int型,4個位元組,在記憶體中存盤方式就是:

int型在記憶體中是以4個位元組為單位存盤的,記憶體中用16進制表示,可以看到a的值為0a(16進制),換算成十進制就是10,
2.大小端位元組序
大小端位元組序是什么?
位元組序就是研究數字的高位在記憶體的高地址還是低地址的問題,
在我們的日常規律中,高位放在低地址是主流,比如123,百位1在左邊低地址,3作為個位在高地址,這個叫做大端位元組序,
計算機存盤中大多數是小端位元組序,就是高位放在高地址,我們還是通過除錯起來理解這個問題:
#include<stdio.h>
#include<stdlib.h>
int main(){
int num = 0x11223344;//直接寫一個16進制,方便觀察
system("pause");
return 0;
}
我們發現這里的表示方法并不是我定義的,而是反過來的,這就是因為大小端位元組序的問題,
我們可以寫一個簡單的函式來判斷我們機器的位元組序是大端還是小端:
#include <stdio.h>
int isBigEnd(int a) {
int* p = &a;
char* p2 = (char*)p;
//此處是強制型別轉換,僅輸出一個位元組的內容
if (*p2 == 0x11) {
printf("大端位元組序");
return 1;
}
printf("小端位元組序");
return 0;
}
int main()
{
int a = 0x11223344;
printf("%d\n", isBigEnd(a));
system("pause");
return 0;
}
3.整形在記憶體中的存盤:原碼、反碼、補碼
3.1原碼、反碼、補碼
這三個形式都是由符號位+數字位構成(第一位是符號位,0為正,1為負)
原碼:就是將數字直接轉化為二進制的形式
反碼:就是將原碼符號位不變,其他的按位取反
補碼=反碼+1
是計算機的實際保存方式
我們依舊舉一個例子來驗證這些:
#include<stdio.h>
#include<stdlib.h>
int main(){
int num = -10;//負數
system("pause");
return 0;
}
我們的得到是:
f6 ff ff ff
已知我們的計算機是小端位元組序所以真正的存盤是:
ff ff ff f6
ff ff ff f6用二進制的方式表示:
1111 1111 1111 1111 1111 1111 1111 0110
-10的原碼:
1000 0000 0000 0000 0000 0000 0000 1010
-10的反碼:
1111 1111 1111 1111 1111 1111 1111 0101
-10的補碼(反碼+1):
1111 1111 1111 1111 1111 1111 1111 0110
ff ff ff f6的二進制表示和-10的補碼一樣
3.2補碼的意義
我們可能會想問為什么是補碼計算機的儲存格式呢?
資料存放記憶體中其實存放的是補碼在計算機系統中,數值一律用補碼來表示和存盤,原因在于,使用補碼,可以將符號位和數值域統一處理;同時,加法和減法也可以統一處理(CPU只有加法器)此外,補碼與原碼相互轉換,其運算程序是相同的,不需要額外的硬體電路,
如果是正數,還是按照原碼的方式存盤
如果是負數,就按照補碼的方式存盤
補碼存在的意義就是為了讓硬體實作更簡單,
把負數按照補碼的格式來存盤就會讓-和+統一,
我們可以借助一個例子來理解:

三、浮點型在記憶體中的存盤決議
1.浮點型資料的存盤規則
我們先來看看專業的規定:
根據國際標準IEEE(電氣和電子工程協會) ,任意一個二進制浮點數V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^s表示符號位,當s=0,V為正數;當s=1,V為負數,
M表示有效數字,大于等于1,小于2,
2^E表示指數位,
舉例來說: 十進制的5.0,寫成二進制是 101.0 ,相當于 1.01×2^2 , 那么,按照上面V的格式,可以得出s=0,M=1.01,E=2,
十進制的-5.0,寫成二進制是 -101.0 ,相當于 -1.01×2^2 ,那么,s=1,M=1.01,E=2,
說了很多的規定,總的就是以科學計數法表示,(只不過改成以2為底數)
S是符號位,0正 1負;
E指數部分;
M有效數字;
也就是± M*2^E
舉個例子:
十進制的5.0,寫成二進制是101.0 ,相當于 1.01×2^2 , 那么,按照上面V的格式,可以得出s=0,M=1.01,E=2,
十進制的-5.0,寫成二進制是 -101.0 ,相當于 -1.01×2^2 ,那么,s=1,M=1.01,E=2,
我們可以分析到:
M占用的位元位越多,表示的資料精度就越高;
E占用的位元位越高,表示的資料范圍就越大,
所以double無論是精度還是范圍都優于float,
如下是float和double的存盤模式:
IEEE 754規定: 對于32位的浮點數,最高的1位是符號位s,接著的8位是指數E,剩下的23位為有效數字M,
對于64位的浮點數,最高的1位是符號位S,接著的11位是指數E,剩下的52位為有效數字M,

2.浮點數的精度損失
使用浮點型經常會出現一個問題,就是得到的小數字往往不是準確值,而是近似值,因為很多無限回圈的數字會精度損失,
我們依舊舉個例子來看看這個精度損失的實際問題:
#include <stdio.h>
int main()
{
float a = 11.0;
float b = a / 3.0;
if (b * 3.0 == a) {
printf("相等!\n");
} else {
printf("不相等\n");
}
system("pause");
return 0;
}
我們知道11.0/3后在*3還是11,但是看運行的結果:

原因就是在做除法的時候資料太多導致溢位,從而導致資料只是近似值,而不是絕對值,
如果在工程專案中出現這種問題,一般是確定誤差在一定范圍內認為他們相等,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/224796.html
標籤:其他

