數據在內存中的存儲方式

數據在內存中的存儲方式

1.爲什麼計算機是二進制存儲

目前我們使用的計算機主要是採用數字集成電路所搭建。由於數字電路只能表示0和1,所以計算機只認識這兩個數字。數字電路是用數字信號完成對數字量進行算數運算和邏輯運算的電路。 計算機無論是數值計算,還是邏輯計算,都主要靠CPU來完成。

2.整形存儲方式

對於整形來說:數據在內存中的存放中都爲補碼形式。
正數的原碼,補碼,反碼相同
負數反碼:將原碼的符號位不變(符號位爲二進制從左至右第一位,正數爲0,負數爲1),其他位按位取反即可。
負數補碼:反碼+1即可。

例1:

#include <stdio.h> 
int main() 
{
 char a = -128;   
 printf("%u\n",a);
 return 0;
}

程序的輸出結果是4294967168

解答:
在win32編譯器環境下:
a先以補碼形式存在,即爲:111111111 11111111 11111111 10000000
先將10000000賦值給 char
之後將char型進行整形提升,即爲:11111111 11111111 11111111 10000000
由於爲%u打印(無符號十進制),故提升後的補碼即爲原碼。
其十進制數即爲4294967168

例2:

#include <stdio.h> 
int main() 
{
 char a = 128;   
 printf("%u\n",a);
 return 0;
}

程序的輸出結果爲:4294967168
解答:
a先以補碼形式存在,即爲:00000000 00000000 00000000 10000000
先將10000000賦值給 char
之後整形提升:11111111 11111111 11111111 10000000
由於爲%u打印(無符號十進制),故提升後的補碼即爲原碼。
其十進制數即爲4294967168
所以結果仍然爲:4294967168

例3:

#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);
 return 0;
}

程序的輸出結果是:-1,-1,255
解答:
首先a,b,c均以32位補碼形式存儲
即爲:11111111 11111111 11111111 11111111

下面分情況進行討論:
a打印
首先將11111111賦值給 char
之後進行整形提升:11111111 11111111 11111111 11111111
求取原碼:10000000 00000000 00000000 00000001
由於c爲有符號打印,即爲-1
b打印
與a打印情況相同
c打印
先將11111111賦值給char
之後整形提升:00000000 00000000 00000000 11111111
由於c爲unsigned char型(無符號字符型),故直接10進制輸出11111111,即爲:255

例4:

#include <stdio.h> 
int main()
{
 int i = -20; 
 unsigned  int  j = 10; 
 printf("%d\n", i + j);
 return 0;
}

程序輸出-10

解答:
首先
i,j均以32位補碼形式在計算機中存儲
其中
i:
原碼:10000000 00000000 00000000 00010100
補碼:11111111 11111111 11111111 11101100
j:
原碼即爲補碼:00000000 00000000 00000000 00001010
i+j的補碼即爲:
11111111 11111111 11111111 11110110
求取原碼:10000000 00000000 00000000 00001010
其10進制結果即爲:-10

例5:
請看下面一段代碼:

#include <stdio.h> 
int main()
{
 unsigned int i; 
 for (i = 9; i >= 0; i--) 
 { 
  printf("%u\n", i); 
 }
 return 0;
}

該程序進入死循環
解答:
首先i=9
在計算機中以補碼形式存儲:
00000000 00000000 00000000 00000111
i自減爲-1時,補碼爲:
11111111 11111111 11111111 11111111
由於i爲無符號類型,故即爲原碼
其10進制結果即爲:4294967295,故程序陷入死循環。

例6:

#include <stdio.h> 
int main() 
{
 char a[1000];
 int i;
 for (i = 0; i<1000; i++)     
 {
  a[i] = -1 - i; 
 }    
 printf("%d", strlen(a));    
 return 0; 
}

該程序輸出255
解答:
當i從-1減到-128,並從-128在減1時,i變爲正值。直到減爲0爲止。(0之後還會繼續進行相減,但strlen遇0停止,所以之後的討論再無意義。)
故從-1到0,共循環255次,故程序輸出255。

例7

#include <stdio.h> 
unsigned char i = 0; 
int main() 
{    
 for(i = 0;i<=255;i++)     
 {        
  printf("hello world\n");    
 }    
 return 0; 
}

該程序陷入死循環
解答:
當i=256時
補碼爲:00000000 00000000 00000000 00000000(最前一位被進了上去,在char類型中無法體現)
即爲0
故程序爲死循環。

3.浮點型在內存中的存儲

浮點數包括: float、double、long double 類型。
根據國際標準IEEE(電氣和電子工程協會) 754,任意一個二進制浮點數V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^s表示符號位,當s=0,V爲正數。當s=1,V爲負數。
M表示有效數字,大於等於1,小於2。
2^E表示指數位。
IEEE 754規定: 對於32位的浮點數,最高的1位是符號位s,接着的8位是指數E,剩下的23位爲有效數字M。 (如下圖)
單精度浮點數存儲模型
同理:對於64位的浮點數,最高的1位是符號位S,接着的11位是指數E,剩下的52位爲有效數字M。
我們目前只討論32位情況。
至於指數E,情況比較複雜。
首先,E爲一個無符號整數(unsigned int) 這意味着,如果E爲8位,它的取值範圍爲0-255;但是,科學計數法中的E是可以出現負數的,所以IEEE 754規定,存入內存時E的真 實值必須再加上一個中間數,對於8位的E,這個中間數是127。比如,2^10的E是10,所以保存成32位浮點數時,必須保存成10+127=137,即10001001.
將E分成3種情況考慮:
E不全爲0或不全爲1
這時,浮點數就採用下面的規則表示,即指數E的計算值減去127,得到真實值,再將有效數字M前 加上第一位的1。 比如: 0.5(1/2)的二進制形式爲0.1,由於規定正數部分必須爲1,即將小數點右移1位, 則爲1.0*2^(-1),其階碼爲-1+127=126,表示爲01111110,而尾數1.0去掉整數部分爲0,補齊0到23位 00000000000000000000000,則其二進制表示形式爲:
0 01111110 00000000000000000000000
E全爲0
這時,浮點數的指數E等於1-127 即爲真實值, 有效數字M不再加上第一位的1,而是還原爲 0.xxxxxx的小數。這樣做是爲了表示±0,以及接近於0的很小的數字
E全爲1
這時,如果有效數字M全爲0,表示±無窮大(正負取決於符號位s);
我們來看下面一段代碼:

例8:

#include <stdio.h> 
int main()
{
  int n = 9;  
  //00000000 00000000 0000000 00001001 
  float *pFloat = (float *)&n;  
  printf("n的值爲:%d\n", n);  //9
  printf("*pFloat的值爲:%f\n", *pFloat);//0.000000
  //以浮點類型視角去讀取數據
  //0 00000000 00000000000000000001001
  *pFloat = 9.0;
  //1.001*2E3
  //0 10000010 00100000000000000000000
  printf("num的值爲:%d\n", n);
  //以整型視角去讀取數據
  //1091567616
  printf("*pFloat的值爲:%f\n", *pFloat);  //9.000000
  return 0;
}

程序的輸出結果爲
輸出結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章