wordpress使用手機號登錄上海網(wǎng)站seoseodian
目錄
1.數(shù)據(jù)類型的詳細介紹
2.整型在內(nèi)存中的存儲:原碼、反碼、補碼
3.大小端字節(jié)序介紹及判斷
4.浮點型的內(nèi)存中的存儲解析
1.數(shù)據(jù)類型的詳細介紹
下述是內(nèi)置類型:
char // 字符數(shù)據(jù)類型
short // 短整型
int // 整型
long // 長整型
long long // 更長的整型
float // 單精度浮點型
double //雙精度浮點型
????????在這里就不說不同數(shù)據(jù)類型在內(nèi)存中所占數(shù)據(jù)類型大小了。注意的是C語言中的沒有字符串的數(shù)據(jù)類型
數(shù)據(jù)類型的意義
1.使用數(shù)據(jù)類型開辟內(nèi)存空間的大小;
2.如何看待內(nèi)存空間的視角。
整形家族:
char
unsigned char //字符在存儲的時候存儲的是ASCLL碼值A(chǔ),ASCLL是整數(shù),
signed char //所以在歸類的時候,字符屬于整型家族short
unsigned short [int]
signed short [int]int
unsigned int
signed intlong
unsigned long [int]
signed long [int] //[]中的數(shù)據(jù)類型是可以省略的
????????注意, char是signed char還是unsigned char 是取決于編譯器的。常見的編譯器上char的類型就是signed char。
????????數(shù)據(jù)元素個數(shù)和數(shù)組的名字發(fā)生變化,數(shù)組的類型也會發(fā)生變化。
????????浮點數(shù)家族:
float
double
????????構(gòu)造類型
> 數(shù)組類型
> 結(jié)構(gòu)體類型 struct
> 枚舉類型 enum
> 聯(lián)合類型 union
????????指針類型
int *pi;
char *pc;
float* pf;
void* pv;
????????void? 表示空類型以為就是沒有什么類型,可以用于函數(shù)的返回類型、函數(shù)的參數(shù)、指針類型。
2.整型在內(nèi)存中的存儲:原碼、反碼、補碼
????????正整型的原反補碼都是相同的,但負整型數(shù)據(jù)的反碼要符號位不變其他位置取反,加上1就會變成補碼,如下 : 補碼也可以先取反再+1得到原碼。負整型補碼轉(zhuǎn)變成原碼有兩種方式。
-1//32位機器
原碼 10000000 00000000 00000000 00000001
反碼 11111111 11111111 11111111 11111110
補碼 11111111 11111111 11111111 11111111補碼轉(zhuǎn)原碼
//方式1
補碼 11111111 11111111 11111111 11111111
反碼 11111111 11111111 11111111 11111110 -1
原碼 10000000 00000000 00000000 00000001 取反//方式2
補碼 11111111 11111111 11111111 11111111
中間 10000000 00000000 00000000 00000000 取反
原碼 10000000 00000000 00000000 00000001 +1
? ? ? ? 整形數(shù)據(jù)在內(nèi)存中是以二進制補碼的形式來存放的。本例子列舉的是32位機器中的存儲。
int a = 20;// 20
// 00000000 00000000 00000000 00010100--原碼
// 00000000 00000000 00000000 00010100--反碼
// 00000000 00000000 00000000 00010100--補碼
// 0x00 00 00 14 轉(zhuǎn)換成16進制 在看看存儲int b= -10;
// -10
// 10000000 00000000 00000000 00001010--原碼
// 11111111 11111111 11111111 11110101--反碼
// 11111111 11111111 11111111 11110110--補碼
// 0xff ff ff f6 轉(zhuǎn)換成16進制
int a = 20;在VS2017下的存儲方式
int b?= -10;在VS2017下的存儲方式
例題,下屬例題都是判斷輸出什么的
1.??
#include <stdio.h>
int main()
{char a = -1;//10000000 00000000 00000000 00000001 原碼//11111111 11111111 11111111 11111110 反碼//11111111 11111111 11111111 11111111 補碼//11111111 截斷,將一個整型數(shù)值賦予一個字符變量的時候要截斷//11111111 11111111 11111111 11111111 補碼// 因為要輸出的是整型,應(yīng)該整型提升,有符號位置應(yīng)該按照符號位來提升 1 補1 0補0//10000000 00000000 00000000 00000000 取反//10000000 00000000 00000000 00000001 原碼signed char b = -1;//和上面相同//10000001 unsigned char c = -1;//10000000 00000000 00000000 00000001 原碼//11111111 11111111 11111111 11111110 反碼//11111111 11111111 11111111 11111111 補碼//11111111 截斷//00000000 00000000 00000000 11111111 //整型提升 無符號為整型提升 補0//存儲方式是一樣的,但輸出的方式是不一樣的 printf("a=%d,b=%d,c=%d", a, b, c); // -1 ,-1,255return 0;
}
2.
#include <stdio.h>
int main()
{char a = -128;
//10000000 00000000 00000000 10000000 原碼
//11111111 11111111 11111111 01111111 反碼
//11111111 11111111 11111111 10000000 補碼
//截取 10000000
//整型提升 看char是有符號的char 整型提升是看原來的數(shù)據(jù)類型來提升的
//11111111 11111111 11111111 10000000 //輸出的是無符號數(shù),可以直接輸出,無符號數(shù)只有正的printf("%u\n", a);// 4294967168return 0;
}
3.
int main()
{char a = 128;// 00000000 00000000 00000000 10000000// 10000000 截斷// 11111111 11111111 11111111 10000000 整型提升printf("%u\n", a);return 0;
}
4.
int main()
{int i = -20;//10000000 00000000 00000000 00010100 原碼//11111111 11111111 11111111 11101011 反碼//11111111 11111111 11111111 11101100 補碼unsigned int j = 10;//00000000 00000000 00000000 00001010 原碼 補碼//11111111 11111111 11111111 11110110//10000000 00000000 00000000 00001001//10000000 00000000 00000000 00001010 //-10printf("%d\n", i + j);//-10 //輸出的形式有符號數(shù) 相加之后本來是無符號數(shù)的return 0;
}
5.
#include <stdio.h>
#include <windows.h>
int main()
{unsigned int i;for (i = 9; i >= 0; i--) //會無限制的循環(huán),i不可能是負數(shù)的,因此會一直大于0{printf("%u\n", i);Sleep(100);} return 0;
} //可以執(zhí)行一下 從零之后就是一個更大的數(shù)字了
6
#include <stdio.h>
int main()
{char a[1000];int i;for (i = 0; i < 1000; i++){a[i] = -1 - i; }//-1 -2 .......-128 127 126 3 2 1 0 128+127=255printf("%d", strlen(a)); //找到'\0' 其ASCLL碼值為 0 找到0 return 0;
}
7.
#include <stdio.h>
unsigned char i = 0;
int main()
{for (i = 0; i <= 255; i++){printf("hello world\n");//死循環(huán)}return 0;
}
循環(huán)限制條件是無符號數(shù),是一定要注意,設(shè)置的限制條件一定要大于0。
3.大小端字節(jié)序介紹及判斷
????????大端(存儲)模式,是指數(shù)據(jù)的低位保存在內(nèi)存的高地址中,而數(shù)據(jù)的高位,保存在內(nèi)存的低地址中;
????????小端(存儲)模式,是指數(shù)據(jù)的低位保存在內(nèi)存的低地址中,而數(shù)據(jù)的高位,,保存在內(nèi)存的高地址中。
????????為什么會存在大端存儲和小端存儲呢?
????????其思想源于格列夫游記,兩個國家由于雞蛋應(yīng)該是先從大頭剝還是從小頭處開始剝皮的問題開始了戰(zhàn)爭。???
? ? ? ? 小端存儲,舉一個例子,下面是一個數(shù)
int a = 0x11223344;
? ? ?下面就是數(shù)據(jù)在VS2017的存儲方式。
????????數(shù)據(jù)的低位應(yīng)該是這樣理解的,123 3就是這個數(shù)據(jù)的低位??磾?shù)據(jù)的低位放在了低地址上,數(shù)據(jù)的高位放在了高地址上。
做個表格詳細了解一下
地址 | 0x007EFBFC | 0x007EFBFD | 0x007EFBFE | 0x007EFBFE |
小端存儲 | 44 | 33 | 22 | 11 |
大端存儲 | 11 | 22 | 33 | 44 |
低地址 | 高地址 |
????????我們再寫一個小程序來判斷一個編輯器是大端存儲還是小端存儲。
#include <stdio.h>
int main()
{int a = 1;//存儲方式是 0x00 00 00 01 如果只取一個字節(jié)就比較好判斷了char *pa = (char *)&a;//()括號中的強制類型轉(zhuǎn)化if (*pa == 1){printf("小端存儲\n");}else{printf("大端存儲\n");}return 0;
}
? ? ? ? 還可以將這個邏輯封裝到一個函數(shù)中,大家可以練習一下,在以后的時候中好的函數(shù)是經(jīng)常調(diào)用的。
封裝函數(shù)
void check_byte()
{int a = 1;if ((char *)&a)printf("小端存儲\n");elseprintf("大端存儲\n");
}
4.浮點型的內(nèi)存中的存儲解析
????????大家想一下 3.14159, 1E10.在內(nèi)存中是如何存儲的?當然和整型是不一樣的。先看下面的例子。
int main()
{
int n = 9;
//00000000 00000000 00000000 00001001
float *pFloat = (float *)&n;
printf("n的值為:%d\n",n);
printf("*pFloat的值為:%f\n",*pFloat);
//以浮點數(shù)的存儲方式取出是不正常值,兩者存儲的方式是不一樣的,*pFloat = 9.0;
printf("num的值為:%d\n",n);
printf("*pFloat的值為:%f\n",*pFloat);
return 0;
}
????????以下是上述代碼的值,可以往后看看浮點型是如何存儲的就理解了,在文章的最后會有解析的。
? ? ? ?浮點數(shù)的存儲規(guī)則
????????根據(jù)國際標準IEEE(電氣和電子工程協(xié)會) 754,任意一個二進制浮點數(shù)V可以表示成下面的形式:
>. (-1)^S * M * 2^E
>. (-1)^s表示符號位,當s=0,V為正數(shù);當s=1,V為負數(shù)。
>. M表示有效數(shù)字,大于等于1,小于2。
>. 2^E表示指數(shù)位
????????舉個例子就明白了,
將十進制的 5.0? ?1> 轉(zhuǎn)換成二級制101.1,相當都1.01×2^2
按上述的格式就是 S=0,表示正數(shù);M=1.01,E=2。如果是-5的話那就是S=-1了。
?再來一個 5.5= 101.1二進制? , 轉(zhuǎn)換成科學計數(shù)法 1.011*2^2? ? (-1)^0*1.011*2^2
S=0, M=1.011, E=2。 0.5 大家思考一下? 注意一下(浮點數(shù)中沒有原反補的概念)
單精度浮點數(shù)存儲模型(4byte)
雙精度浮點型(8byte)
特殊規(guī)定
? ? ? 1. M值的存儲方式
????????前面說過, 1≤M<2 ,也就是說,M可以寫成 1.xxxxxx 的形式,其中xxxxxx表示小數(shù)部分。IEEE 754規(guī)定,在計算機內(nèi)部保存M時,默認這個數(shù)的第一位總是1,因此可以被舍去,只保存后面的xxxxxx部分。 (此種方式可以提升精度)
????????比如保存1.01的時候,只保存01,等到讀取的時候,再把第一位的1加上去。這樣做的目的,是節(jié)省1位有效數(shù)字。以32位浮點數(shù)為例,留給M只有23位,將第一位的1舍去以后,等于可以保存24位有效數(shù)字。
????????2.?E的存儲方式??????
????????E為一個無符號整數(shù)是無法判讀E是正負的。如果E為8位,它的取值范圍為0~255;如果E為11位,它的取值范圍為0~2047。但是科學計數(shù)法中的E是可以出現(xiàn)負數(shù)的,所以IEEE 754規(guī)定,存入內(nèi)存時E的真實值必須再加上一個中間數(shù),對于8位的E,這個中間數(shù)是127;對于11位的E,這個中間數(shù)是1023。比如,2^10的E是10,所以保存成32位浮點數(shù)時,必須保存成10+127=137,即10001001。
????????指數(shù)E從內(nèi)存中中取出還可以再分為三種情況
????????1.E不全為0或者不全為1
這時,浮點數(shù)就采用下面的規(guī)則表示,即指數(shù)E的計算值減去127(或1023),得到真實值,再有效數(shù)字M前加上第一位的1。 比如: 0.5(1/2)的二進制形式為0.1,由于規(guī)定正數(shù)部分必須為1,即將小數(shù)點右移1位,則為1.0*2^(-1),其階碼為-1+127=126,表示為01111110,而尾數(shù)1.0去掉整數(shù)部分為0,補齊0到23位00000000000000000000000,則其二進制表示形式為:
0 01111110 00000000000000000000000
????????2.E全為0
????????這時,浮點數(shù)的指數(shù)E等于1-127(或者1-1023)即為真實值, 有效數(shù)字M不再加上第一位的1,而是還原為0.xxxxxx的小數(shù)。這樣做是為了表示±0,以及接近于0的很小的數(shù)字。
????????3.E全為1
????????這時,如果有效數(shù)字M全為0,表示±無窮大(正負取決于符號位s).
實際的例子?
5.5
float f = 5.5f;// 轉(zhuǎn)換成SME的形式 (-1)^0 * 1.011 * 2^2//S = 0;M = 1.011; E = 2; 2+127=129//0 10000001 01100000000000000000000//0100 0000 1011 0000 0000 0000 0000 0000// 4 0 b 0 0 0 0 0
4.小節(jié)開始的例題
#include <stdio.h>
int main()
{int n = 9;float *pFloat = (float *)&n;//00000000 00000000 00000000 00001001//0 00000000 0000000 00000000 00001001//(-1)^0 * 0.00000000000000000001001 * 2^-126 相當于0了printf("n的值為:%d\n", n);printf("*pFloat的值為:%f\n", *pFloat);*pFloat = 9.0;//9.0的存儲方式//1001二級制 1.001^3 3+127=130//0 1000 0010 00100000000000000000000//01000001000100000000000000000000 存儲方式printf("num的值為:%d\n", n);printf("*pFloat的值為:%f\n", *pFloat);//1,091,567,616return 0;
}
????????由于存儲方式的不同和訪問方式的不同,會造成數(shù)據(jù)錯誤。