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