數據在內存中的存儲(詳細版)


1、整型在內存中的存儲

(32位系統)spa

在VS2013中,使用調試->窗口->內存,來觀察內存的具體狀況。
在這裏插入圖片描述
讓咱們經過內存窗口來看看整型在內存中的存儲,
定義一個整形變量int a= 10;


翻譯


注意:能夠在地址欄中使用&來找到目標變量的內存狀況。
在這裏插入圖片描述
3d


a的地址:0x00EFF980
在這裏插入圖片描述
調試

int型在內存中是以4個字節爲單位存儲的,內存中用16進製表示。能夠看到a的值爲0a(16進制),換算成十進制就是10。code


一、字節序

爲何會有大小端模式之分呢?blog

    這是由於在計算機系統中,咱們是以字節爲單位的,每一個地址單元都對應着一個字節,一個字節爲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;
}

二、原碼補碼反碼

計算機中的符號數有三種表示方法即原碼、補碼、反碼。正數的原、反、補碼都相同。
三種表示方法均有符號位和數值位兩部分,符號位都是用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)
在這裏插入圖片描述




在這裏插入圖片描述

2、浮點型在內存中的存儲

一、浮點型

根據國際標準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較多。

二、浮點數的比較

使用這種方式來存儲的時候,會帶來一個很大的問題,保存的小數每每不是一個精確值,而只是一個近似值。

示例:

#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;
}

在這裏插入圖片描述

相關文章
相關標籤/搜索