學習目標:
剖析資料在記憶體中的存盤,本章重點:
- 資料型別詳細介紹
- 整形資料在記憶體中的存盤
- 大小端位元組序介紹及判斷
- 浮點型資料在記憶體中的存盤
學習內容:
①:
| 整形家族 | char(本質為ASCII的存盤)、short、int、long、 long long;均有signed和unsigned.編譯器默認為signed |
| 浮點型家族 | float、double |
②:何為有符號、無符號?
舉個栗子:vs2019為例
char:默認為signed char,當有char a=1;先寫32位原碼,由于正數原、反、補碼一致,所以int型的1的低位(8位)bit位內的資料被截斷,然后存至char所申請的空間,此時的8為bit位的最高位為符號位,這對char、short類的預設整型精度的資料型別來說,做運算式運算時,發生整型提升至關重要!上代碼:
#include <stdio.h>
int main()
{
unsigned char c1 = 255;
printf("%d\n", c1);//作%d列印,char、short型別資料亦作整型提升
//8為bit存滿1時,剛好為255:11 11 11 11
//由于是unsigned char,上述最高位為有效位,所以做整型提升時:
//按正數提升:00000000 00000000 00000000 11111111
//對上述補碼(等價于原碼)列印,直接翻譯即可:255
char c2 = 255;
//上述8位bit位的最高位為符號位,故作負數的整型提升:
//11111111 11111111 11111111 11111111(補碼)
//翻譯為原碼(列印):10000000 00000000 00000000 00000001
//上述結果為-1;
printf("%d\n", c2);
return 0;
}
對signed char和unsigned char型別記憶體空間所能存盤的十進制數作總結:
(a):unsigned char:8位有效位:最大數為:2^8-1=255(因為有個0,所以減一);
(b):signed char:最高位為0或1,為0為正數,為1為負數,兩者在256(絕對值)各占一半,即負數范圍為:-1?-128;而正數由于有個0,所以其范圍為:0?127.
綜合上述可知:signed char 所能表示的范圍為:-128?127(-128為:10000000?補碼)
將上述推演規律拓展至short,類似,直接給出其范圍:-32768?32767(signed)
②:除了上述的整型、浮點型,這里還有一個構造型別(自定義)
| 陣列型別(隨著元素型別、元素個數變化) |
| 結構體型別 |
| 列舉型別 |
| 聯合型別 |
③:指標型別
意義在于:解參考及訪問位元組數會受其影響,
④:整型在記憶體中的存盤:
統一形式為補碼(意義:可將符號位和數值域統一處理,其與原碼相互轉換,運算程序相同,無需額外電路)
⑤:位元組序
顧名思義:以位元組為單位來排序,
補碼的低位放在低地址處:小端位元組序,
補碼的高位放在低地址處:大端位元組序,
例題:設計一個程式判斷當前機器的位元組序:(利用指標總是指向“小位元組”的特點):
#include <stdio.h>
int main()
{
int a = 1;
char* p = (char*)&a;//&a為int*,強轉成char*再賦給p
if (*p == 1)
{
printf("小端\n");
}
else
printf("大端\n");
return 0;
}
note:%d和%u列印時,都是針對發生整型提升后的最高位而言的,
例題1:(列印結果時什么?)
#include <stdio.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
return 0;
}

原因:i>=0;i列印9-0沒問題,再--變成-1時:補碼全為1(32位),存進unsigned int申請的空間,此時的二進制位是沒有符號位的,翻譯成原碼(無符號位時原反補全等):2^32-1=4294967295,這就導致在for回圈的判斷部分i>=0進行時, 為真,繼續列印!
note:自己動手計算記憶體中的數是多少時遵循一個原則:記憶體中的都是補碼,顯示在螢屏上的都是原碼!怎么把補碼翻譯成原碼,關鍵就看補碼的資料型別是有無符號位了,
例題2:(列印結果時什么?)
#include <stdio.h>
#include <string.h>
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d",strlen(a));
return 0;
}
分析:a[i]依次為:-1、-2、...、-128(因為陣列元素型別為char,負數的上限為-128,此時的補碼為:10 00 00 00);再減一:01 11 11 11翻譯成原碼:2^7-1=127.之后再繼續減減的操作直至0.
strlen從a進入,將元素當作unsigned char來翻譯,只要不是‘\0’(ASCII為0(補碼)),統統每進一位就加一,所以說:計數至0.strlen功能完成,那此時的字符個數是:128+127=255個(0不算一個),
⑥:浮點型資料在記憶體中的存盤
準則:IEEE754:任意一個二進制浮點數V可以表示成以下形式:
(-1)^S*M*2^E
s:表正負:0為正,1為負
M:有效數字,范圍:1<=M<2
E:指數位(10^3在十進制中的指數位就是3,二進制就是2^指數位)
5.5寫成二進制:101.1再科學計數法:1.011*2^2.再寫成上述標準格式:(-1)^0*1.011*2^2
那s、m、e分別為:0、1.011、2
難以存盤的二進制小數(浮點數):3.3
因為小數點后一位為:2^-1
小數點后兩位為:2^-2
...
存盤:
float:(4位元組,32位bit):從低地址至高地址依次存S、E、M,各自分配的bit的數量為:1、8、23
double:(8位元組,64位bit):亦依次存S、E、M,各自分配的bit數量為:1、11、52
對S/E/M存盤規則的介紹:
S:0/1存進低地址首位bit中,無需多說
M:由于其范圍為1<=M<2;即必為1.幾,敢情1直接不存了,只存小數點后面的.幾的“幾”,等到讀取時再把這個省略的1補上,這么做的目的是:多一位有效位!還原(讀取)時記得加一,
E:首先它是一個unsigned int :有效位則為8位,范圍則來到:0?255,若是double,更是來到:0?2047,由于科學計數法是允許E為負數的,對此,unsigned int與負數存在矛盾,IEEE754則對此作出規定:存入記憶體的E值須再加上0?255或者0?2047的一個中間數,即127和1023.再存進屬于E的那塊空間,如2^10,E是10,存的話,float:存的是10+127=137的補碼,double存的是:10+1023=1033的補碼,
舉例:存float的0.5:
S:0
E:-1+127=126:補碼(等價于原碼):01 11 11 10
M:1.0:1不要就存23個0:00000000 00000000 0000000
總的:
0 01111110 00000000000000000000000
對存于記憶體中的二進制浮點數的讀取:
分情況:
(a):E不全為0或不全為1(最一般的情況)
由上述:E的真實值則為記憶體中的補碼翻譯成原碼后再減那個中間數(float還是double?),M再加個1,
(b):E全為0:上述可知E是加過中間數作存盤的,加完還全是0,你說剛開始的E是有多小!?,所以說此時的浮點數,幾乎接近于0;此時的M不必再加1還原了,直接列印吧,
(c):E全為1:這時:如果有效數字全為0表示±無窮大,
對浮點數存盤理解的一個經典案例:
#include <stdio.h>
int main()
{
int n = 9;
//9的補碼:00000000 00000000 00000000 00001001
float* pfloat = (float*)&n;
printf("n的值為:%d\n", n);//為9不難理解
printf("pfloat的值為:%f\n", *pfloat);
//以%f列印9的補碼,此時的補碼被視作浮點型資料的存盤方式:
//0 00000000 00000000000000000001001
//此時屬于E全為0的情況,E真實值為0-127=-127,M為0.00000000000000000001001
//還原出的數字非常接近于0;而%f只能精確到小數點后6位,故只可列印0.000000
*pfloat = 9.0;
//9.0寫成二進制數:(-1)^0*1.001*2^3
//存:0 10000010 00100000000000000000000
printf("num的值為:%d\n", n);
//以%d的形式去解讀上述補碼,為一個正數,直接當做原碼列印:1091567616
printf("*pfloat的值為:%f\n", *pfloat);
//9.000000
return 0;
}
運行結果也確實是:

學習時間:
2021.10.7
學習產出:
1、 技術筆記 2 遍
2、CSDN 技術博客 31篇
3、 gitee
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/306279.html
標籤:其他
下一篇:TopK演算法(堆的思想)
