資料在記憶體中的存盤
- 一、整型在記憶體中的存盤
- 1、位元組序
- (1)小端位元組序
- (2)大端位元組序
- (3)寫一個程式判斷是否為大端位元組序
- 2、原碼補碼反碼
- (1)補碼
- (2)補碼的意義
- 二、浮點型在記憶體中的存盤
- 1、浮點型
- 2、浮點數的比較
一、整型在記憶體中的存盤
(32位系統)
在VS2013中,使用除錯->視窗->記憶體,來觀察記憶體的具體情況,

讓我們通過記憶體視窗來看看整型在記憶體中的存盤,
定義一個整形變數int a= 10;,
注意:可以在地址欄中使用&來找到目標變數的記憶體情況,

a的地址:0x00EFF980

int型在記憶體中是以4個位元組為單位存盤的,記憶體中用16進制表示,可以看到a的值為0a(16進制),換算成十進制就是10,
1、位元組序
為什么會有大小端模式之分呢?
??? 這是因為在計算機系統中,我們是以位元組為單位的,每個地址單元都對應著一個位元組,一個位元組為8bit,但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對于位數大于8位的處理器,例如16位或者32位的處理器,由于暫存器寬度大于一個位元組,那么必然存在著一個如果將多個位元組安排的問題,因此就導致了大端存盤模式和小端存盤模式,
(1)小端位元組序
小端(存盤)模式:
資料的低位保存在記憶體的低地址中,而資料的高位,保存在記憶體的高地址中,
我們輸入一個十六進制數,來觀察一下在記憶體中的情況
int a = 0x11223344
可以看到高位11保存在記憶體的高地址中,低位44保存在記憶體的低地址,
(2)大端位元組序
大端(存盤)模式:
資料的低位保存在記憶體的高地址中,而資料的高位,保存在記憶體的低地址中,
int a = 0x11223344;
以上例子在大端位元組序中的存盤是這樣的:
在日常生活中,大部分的pc都是使用小端位元組序,
(3)寫一個程式判斷是否為大端位元組序
規定:回傳0不是,回傳1是,
#include <stdio.h>
int isBigEnd(int a) {
int* p = &a;
char* p2 = (char*)p;
if (*p2 == 0x11) {
return 1;
}
return 0;
}
int main()
{
int a = 0x11223344;
printf("%d\n", isBigEnd(a));
system("pause");
return 0;
}
2、原碼補碼反碼
計算機中的符號數有三種表示方法即原碼、補碼、反碼,正數的原、反、補碼都相同,
三種表示方法均有符號位和數值位兩部分,符號位都是用0表示“正”,用1表示“負”,而數值位三種表示方法各不相同,
原碼:直接將二進制按照正負數的形式翻譯成二進制就可以,
反碼:將原碼的符號位不變,其他位依次按位取反就可以得到了,
補碼:反碼+1就得到補碼,
(1)補碼
對于整形來說:資料存放記憶體中其實存放的是補碼,
-10在記憶體中的存盤:
在記憶體中我們可以看到在記憶體的存盤的值為 f6 ff ff ff ,
在上面已經為大家介紹了小端位元組序,因為我的計算機是小端位元組序,
所以它的值就為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轉換成二進制的結果相同,
(2)補碼的意義
為什么對于整形來說,資料存放記憶體中其實存放的是補碼呢?
???資料存放記憶體中其實存放的是補碼在計算機系統中,數值一律用補碼來表示和存盤,原因在于,使用補碼,可以將符號位和數值域統一處理;同時,加法和減法也可以統一處理(CPU只有加法器)此外,補碼與原碼相互轉換,其運算程序是相同的,不需要額外的硬體電路,
補碼存在的意義就是讓硬體實作簡單,
比如:把負數按補碼表示,可以統一±為+,
例子:
1-10=1+(-10)


二、浮點型在記憶體中的存盤
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,
IEEE 754規定:
對于32位的浮點數,最高的1位是符號位s,接著的8位是指數E,剩下的23位為有效數字M,
對于64位的浮點數,最高的1位是符號位S,接著的11位是指數E,剩下的52位為有效數字M,

M占用的位元位越多,資料精度越高,
E占用的位元位越多,資料范圍越大,
所以在實際開發中使用double較多,
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.0*3.0肯定等于11.0,
但是我們看看運行結果:
所以,浮點數在記憶體中存盤的時候,很多時候是有誤差的,
正確的比較方法:
使用做差的方法,然后判斷差值是不是在允許誤差范圍內,如果在的話,就相等,
#include <stdio.h>
#define N 1e-4
int main()
{
float a = 11.0;
float b = a / 3.0;
if (b * 3.0 - a < N && b * 3.0 - a > -N) {
printf("相等, 此處不是嚴格相等, 而是允許誤差\n");
} else {
printf("不相等\n");
}
system("pause");
return 0;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/214484.html
標籤:其他
上一篇:研究生學習生活日記——第五次組會
