国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【數(shù)據(jù)類型存儲(chǔ)原理】數(shù)據(jù)的存儲(chǔ) - 深度剖析數(shù)據(jù)在內(nèi)存中的存儲(chǔ)

yuanzhanghu / 2816人閱讀

摘要:數(shù)據(jù)的存儲(chǔ)前言數(shù)據(jù)類型匯總整型家族浮點(diǎn)型家族自定義類型指針類型。整型家族注在之后的標(biāo)準(zhǔn)規(guī)定,將類型數(shù)據(jù)劃分為整型家族,因?yàn)樽址趦?nèi)存中會(huì)將其轉(zhuǎn)化為碼值進(jìn)行存儲(chǔ)。

?前言

我們?cè)谇么a的時(shí)候總是會(huì)定義各種變量,對(duì)各種數(shù)據(jù)進(jìn)行存儲(chǔ),比如int a = 10;就是將10這個(gè)數(shù)據(jù)存放進(jìn)變量a中,而變量a,就是我們?cè)趦?nèi)存中申請(qǐng)開辟的一塊空間。
在內(nèi)存中如何開辟空間給變量的問題博主已經(jīng)在函數(shù)棧幀里用反匯編的方式將其原理剖析了,具體可看圖解函數(shù)棧幀 - 函數(shù)棧幀的創(chuàng)建及銷毀
本文將進(jìn)一步剖析在已經(jīng)開辟好存儲(chǔ)單元的情況下,各種數(shù)據(jù)是如何存儲(chǔ)的。


在了解數(shù)據(jù)如何存儲(chǔ)之前,應(yīng)該先了解我們常見的數(shù)據(jù)類型。

?數(shù)據(jù)類型匯總

在C99標(biāo)準(zhǔn)中,我們可將數(shù)據(jù)類型劃分為以下幾大類。

  1. 整型家族
  2. 浮點(diǎn)型家族(實(shí)型家族)
  3. 自定義類型(構(gòu)造類型)
  4. 指針類型
  5. 空類型

下面一一介紹這五種類型的基本情況。

?整型家族

char		unsigned char		signed charshort		unsigned short [int]		signed short [int]int		unsigned int		signed intlong		unsigned long [int]		signed long [int]

注:在C99之后的標(biāo)準(zhǔn)規(guī)定,將char類型數(shù)據(jù)劃分為整型家族,因?yàn)樽址趦?nèi)存中會(huì)將其轉(zhuǎn)化為ASCII碼值進(jìn)行存儲(chǔ)。

如上所示,所有的整型家族都被分為有符號(hào)整型和無符號(hào)整型,并且signed都是可以被省略的,換言之,signed int完全等價(jià)于int,其他以此類推,但其中有一個(gè)例外: char類型和signed char并不等價(jià),只寫一個(gè)char ch = 0;我們將無法分辨這個(gè)ch變量到底是有符號(hào)字符型還是無符號(hào)字符型,他完全取決于編譯器,但經(jīng)博主測試,大部分編譯器下char類型都被編譯器翻譯為有符號(hào)的char類型。

在C99中還引入了long long - 長長整型,用法和long類型一致,但C語言語法規(guī)定,sizeof(long)<= sizeof(long long),而long類型所占內(nèi)存大小為4/8字節(jié),所以long long類型所占內(nèi)存空間大小一定為8個(gè)字節(jié)。

?浮點(diǎn)型家族

floatdouble

浮點(diǎn)型家族只有float和double這兩種類型,float類型所占空間大小為4byte,double類型所占空間大小為8byte。

他們之間的區(qū)別除了所占空間大小不同之外還有精度的區(qū)別,float稱為單精度浮點(diǎn)型,有效精度為小數(shù)點(diǎn)后6位,而double類型稱為雙精度浮點(diǎn)型,精確到小數(shù)點(diǎn)后15位,但其有效數(shù)字只有11位左右。

?自定義類型

> 數(shù)組類型> 結(jié)構(gòu)體類型 struct> 枚舉類型 enum> 聯(lián)合類型 union

這里可能會(huì)有很多人無法李姐為什么數(shù)組類型也被劃分為自定義類型,這里稍微做一些解釋。

我們知道數(shù)組類型的變量定義形式:數(shù)據(jù)類型+數(shù)組名+[數(shù)組大小];

如:

int arr[10] = { 0 };

這里可能會(huì)讓很多人產(chǎn)生誤區(qū),認(rèn)為arr數(shù)組的類型是int類型,也就把這條語句理解為是int類型的、數(shù)組名為arr的數(shù)組大小為10的數(shù)組,其實(shí)不然,這個(gè)數(shù)組的數(shù)組名確實(shí)是arr,但其數(shù)據(jù)類型是int [10],這里可能讓大部分人無法接受,

舉個(gè)簡單的例子即可解釋:

我們知道,sizeof操作符是用來計(jì)算所占內(nèi)存空間大小的,其操作數(shù)既可以是變量名,也可以是變量類型。

#define _CRT_SECURE_NO_WARNINGS 1#include int main(){	int a = 10;	printf("%d/n", sizeof(a));	printf("%d/n", sizeof(int));	return 0;}

這兩種寫法都正確,打印結(jié)果為:

而對(duì)于數(shù)組,操作數(shù)也同樣可以是數(shù)組名或者數(shù)組類型:

#define _CRT_SECURE_NO_WARNINGS 1#include int main(){	/*int a = 10;	printf("%d/n", sizeof(a));	printf("%d/n", sizeof(int));*/	int arr[10] = { 0 };	printf("%d/n", sizeof(arr));	printf("%d/n", sizeof(int[10]));	return 0;}

其打印結(jié)果為:


這么一來,就驗(yàn)證了int [10]是數(shù)組類型。

知道了這點(diǎn),解釋為什么數(shù)組類型是自定義類型就更清晰了,用上面解釋的結(jié)論就可以知道,int arr[10]和int arr[9]的數(shù)組類型不同,并不都是int類型的,數(shù)組大小是我們程序員人為規(guī)定的,所以可以把他劃分為自定義類型。

其他的自定義類型比較明顯,這里就不一一解釋。

???指針類型。

指針類型很特殊。

我們常說的指針有兩個(gè)含義:

  1. 某一個(gè)變量的地址,也就是其在內(nèi)存中的編號(hào),我們可稱其為指針。
  2. 用于存放地址(編號(hào))的變量,我們稱其為指針變量,常簡稱指針。

指針類型的定義方式為:

數(shù)據(jù)類型+*(用于標(biāo)識(shí)指針類型)+指針變量名

常見的指針類型有:

int* pi;char* pc;float* pf;void* pv;

這里著重介紹一點(diǎn),指針變量賦值大部分都是取出某變量地址存放進(jìn)指針變量,如int pc = &c;

但有一個(gè)例外:

int main(){	char* pc = "hello world";	printf("%c/n", *pc);	return 0;}

這里之間將一個(gè)字符串常量賦值給指針變量pc,我們知道,字符串常量時(shí)放在常量區(qū)的,他的值不可修改,并且這里的字符串加上隱藏的’/0’總共是12個(gè)字節(jié),而我們的指針變量根據(jù)平臺(tái)的不同只能是4/8個(gè)字節(jié),怎么都不可能放的下這個(gè)字符串常量,所以這么理解是錯(cuò)誤的。

我們將其打印看看結(jié)果:


打印結(jié)果為單字母h,這么一來其實(shí)就解釋的通了,將整個(gè)常量字符串賦值給指針變量,其實(shí)并不會(huì)把整個(gè)字符串放進(jìn)去,而是把整個(gè)字符串的首地址賦給指針變量,比較指針存放的就是地址,這和將字符數(shù)組名賦值給指針變量類似,存放的都是首元素地址。

?空類型

void 用于表示空類型(無類型)
通常應(yīng)用于函數(shù)的返回類型、函數(shù)的參數(shù)、指針類型。

下面舉幾空類型的例子幫助理解:

  • 返回類型:
void test(int x){	printf("%d/n", x);}int main(){	int a = 10;	test(a);	return 0;}

這里test函數(shù)的返回類型就是void。

  • 函數(shù)的參數(shù):
int test(void){	return 1;}int main(){	int ret = test();	printf("%d/n", ret);	return 0;}

這個(gè)代碼就是將函數(shù)的參數(shù)置為空,表示不允許主調(diào)函數(shù)傳參,如果非要傳參,編譯器將給出警告。

int test(void){	return 1;}int main(){	int a = 10;	int ret = test(a);	printf("%d/n", ret);	return 0;}

  • 指針類型:
void* pc;

表示定義一個(gè)指針pc,但他什么都不指向,作為一個(gè)空指針存在。


?大小端字節(jié)序說明

我們知道不管是什么樣的數(shù)據(jù),最終都會(huì)被編譯器編譯為二進(jìn)制機(jī)器碼進(jìn)行存儲(chǔ),并且我們的內(nèi)存是以字節(jié)為最小存儲(chǔ)單元?jiǎng)澐侄M(jìn)行存儲(chǔ)的,那么就存在了一個(gè)問題,數(shù)據(jù)以字節(jié)為單位進(jìn)行存儲(chǔ)的時(shí)候,是以怎樣的順序進(jìn)行存儲(chǔ)的呢?這就引出了大小端字節(jié)序的概念。

?出現(xiàn)大小端字節(jié)序的原因

為什么會(huì)有大小端字節(jié)序模式之分呢?這是因?yàn)樵谟?jì)算機(jī)系統(tǒng)中,我們是以字節(jié)為單位的,每個(gè)地址單元都對(duì)應(yīng)著一個(gè)字節(jié),一個(gè)字節(jié)為8bit位。但是在C語言中除了8bit的char類型之外,還有16bit的short類型,32bit的long類型(要看具體的編譯器,64位平臺(tái)long類型為64位),另外,對(duì)于位數(shù)大于8位的處理器,例如16位或者32位的處理器,由于寄存器的寬度大于一個(gè)字節(jié),那么必然存在著一個(gè)如何將多個(gè)字節(jié)安排的問題。因此就導(dǎo)致了大端存儲(chǔ)模式和小端存儲(chǔ)模式。

例如:一個(gè)16bit位的short類型變量x ,在內(nèi)存中的地址為0x0010,變量x 的值為0x1122 ,那么0x11為高字節(jié),0x22為低字節(jié)。對(duì)于大端模式,就將 0x11放在低地址中,即0x0010中,0x22 放在高地址中,即0x0011中。小端模式,剛好相反。我們常用的X86(32位平臺(tái))結(jié)構(gòu)是小端模式,而KEILC51則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬件來選擇是大端模式還是小端模式。

?字節(jié)序的概念

字節(jié)序,即字節(jié)順序,又稱端序或尾序,在計(jì)算機(jī)科學(xué)領(lǐng)域中,指「存儲(chǔ)器」中或者「數(shù)字通信鏈路」中,組成多字節(jié)的字節(jié)排列順序 。在幾乎所有的機(jī)器上,多字節(jié)對(duì)象都被存儲(chǔ)為連續(xù)的字節(jié)序列 。例如在C語言中,一個(gè) int類型的變量x地址為0x100,那么其對(duì)應(yīng)的地址表達(dá)式&x的值為0x100 且 x 的4個(gè)字節(jié)將被存儲(chǔ)在存儲(chǔ)器的0x100, 0x101, 0x102, 0x103位置。字節(jié)的排列方式有2個(gè)通用規(guī)則。

  1. 順序排列 - 大端字節(jié)序
  2. 逆序排列 - 小端字節(jié)序

上面的文字描述也許過于抽象,接下來用較為容易理解的方式分別簡單的介紹大端字節(jié)序和小端字節(jié)序的概念。

?大小端字節(jié)序

所謂大小端字節(jié)序,就是將多字節(jié)數(shù)據(jù)中的高低字節(jié)位按不同順序存放在內(nèi)存中的高低地址處,相當(dāng)于順(逆)序存放。接下來博主將把上述抽象概念劃分逐一介紹:

  1. 首先理解什么叫做多字節(jié)數(shù)據(jù)。

我們知道一個(gè)數(shù)據(jù)根據(jù)大小不同被劃分為不同的數(shù)據(jù)類型,各數(shù)據(jù)類型所占字節(jié)數(shù)不同,我們也就據(jù)此根據(jù)數(shù)據(jù)字節(jié)大小來將其存放于不同的數(shù)據(jù)類型中。

比如字符類型 - 其擴(kuò)展之后的ASCII碼值為0~255,我們知道一個(gè)字節(jié)是8位,按照無符號(hào)字符型的理解也就是從00000000 ~ 11111111,剛好是0 ~ 255,所以字符類型被稱為單字符類型數(shù)據(jù)。

而十六進(jìn)制數(shù),如:0x11223344則為多字節(jié)數(shù)據(jù),其中有4個(gè)字節(jié),分別是0x11、0x22、0x33、0x44,像這樣的數(shù)據(jù)則被稱為多字節(jié)數(shù)據(jù)。


  1. 理解什么叫做多字節(jié)數(shù)據(jù)的高字節(jié)位。

在一個(gè)二進(jìn)制序列中,

如:01010110101001011010100101101001

我們把前方高亮部分的0101稱為高字節(jié)位,把后端加刪除線的1001 部分稱為低字節(jié)位,以此區(qū)分。

其實(shí)很好理解,因?yàn)樽詈笠粋€(gè)1的的權(quán)重為20,也就是2的0次方,而第一個(gè)0的權(quán)重為231,也就是2的31次方,以此來區(qū)分高低字節(jié)位也是很不錯(cuò)的選擇。


接下來介紹大小端字節(jié)序的存儲(chǔ)方式:

大端字節(jié)序

所謂大端字節(jié)序,就是將處于高字節(jié)位的數(shù)據(jù)存放在內(nèi)存的低地址處,將處于低字節(jié)位的數(shù)據(jù)存放在內(nèi)存的高地址處

如今給一數(shù)據(jù):0x11223344

在內(nèi)存中的存放形式為:


以這樣的形式存放的模式,就稱為大端存儲(chǔ)模式,這樣的存放順序,也就被稱為大端字節(jié)序。

小端字節(jié)序

所謂小端字節(jié)序,就是將處于高字節(jié)位的數(shù)據(jù)存放在內(nèi)存的高地址處,將處于低字節(jié)位的數(shù)據(jù)存放在內(nèi)存的低地址處

今給一數(shù)據(jù):0x11223344

在內(nèi)存中的存放形式為:


以這樣的形式存放的模式,就稱為小端存儲(chǔ)模式,這樣的存放順序,也就被稱為小端字節(jié)序。

在博主使用的VS2019編譯器上,采用的就是小端字節(jié)序:

例:

int main(){	int a = 0x0000ff40;	return 0;}

調(diào)試 - 內(nèi)存窗口(&a):


0x001DFEFC就是該代碼中a變量的地址,存放情況為40 ff 00 00。

也就是小端存儲(chǔ)模式。

???百度系統(tǒng)工程師筆試題(通過編程判斷該編譯器為大端存儲(chǔ)還是小端存儲(chǔ))

百度2015年系統(tǒng)工程師筆試題:

請(qǐng)簡述大端字節(jié)序和小端字節(jié)序的概念,設(shè)計(jì)一個(gè)小程序來判斷當(dāng)前機(jī)器的字節(jié)序。(10分)

該題前半部分在上文其實(shí)已經(jīng)解決了,這里博主將分析問題,并實(shí)現(xiàn)代碼。

?問題分析

要判斷編譯系統(tǒng)到底是大端存儲(chǔ)還是小端存儲(chǔ),其實(shí)并不復(fù)雜。

如0x11223344

如果是在大端存儲(chǔ)模式下:
存儲(chǔ)方式為:11 22 33 44

如果是在小端存儲(chǔ)模式下:
存儲(chǔ)方式為:44 33 22 11

所以其實(shí)只需要知道第一個(gè)字節(jié)的內(nèi)容到底是11還是44就可以判斷了。
但這樣的數(shù)據(jù)太過于復(fù)雜,不如換簡單一點(diǎn)的數(shù)字,比如1。

1的高字節(jié)位就是00,低字節(jié)位就是01,比較好判斷。

?代碼演示

int check_sys(int x){	return *(char*)&x;}int main(){	int a = 1;	//約定:	//如果是大端,返回0	//如果是小端,返回1	int ret = check_sys(a);	if (ret)	{		printf("是小端存儲(chǔ)模式/n");	}	else	{		printf("是大端存儲(chǔ)模式/n");	}	return 0;}

運(yùn)行結(jié)果:

之前也分析了,我的編譯器VS2019是小端存儲(chǔ)模式,所以代碼的結(jié)果正確,下面分析代碼。

?代碼分析

  1. 想要在4個(gè)字節(jié)中拿到第一個(gè)字節(jié),只需要在取地址時(shí)將整型強(qiáng)制類型轉(zhuǎn)換為字符型即可,拿到存放第一個(gè)字節(jié)的地址后對(duì)其解引用便可拿到第一個(gè)字節(jié)數(shù)據(jù)。

  2. 如果拿到的是01,說明存儲(chǔ)方式是01 00 00 00,也就是小端存儲(chǔ)模式,反之則為大端存儲(chǔ)模式。

這里如果有沒有講清楚的地方,歡迎評(píng)論區(qū)留言或者私信博主解決嗷。


?整型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)

數(shù)據(jù)在內(nèi)存中的存儲(chǔ)遵循一定的法則,而整型數(shù)據(jù)和浮點(diǎn)型數(shù)據(jù)在內(nèi)存中所遵循的法則是不同的,這里我們先介紹整型數(shù)據(jù)在內(nèi)存中是如何存儲(chǔ)的。

介紹整型數(shù)據(jù)的存儲(chǔ)需要先引進(jìn)一個(gè)概念:原反補(bǔ)碼。

?原碼、反碼、補(bǔ)碼

計(jì)算機(jī)中的有符號(hào)數(shù)有三種表示方法,即原碼、反碼和補(bǔ)碼。三種表示方法均有符號(hào)位和數(shù)值位(或稱有效位)兩部分,符號(hào)位都是用0表示“正”,用1表示“負(fù)”,而數(shù)值位,三種表示方法各不相同。在計(jì)算機(jī)系統(tǒng)中,數(shù)值一律用補(bǔ)碼來表示和存儲(chǔ)。原因在于:使用補(bǔ)碼,可以將符號(hào)位和數(shù)值域統(tǒng)一處理;同時(shí),加法和減法也可以統(tǒng)一處理。
而補(bǔ)碼其實(shí)是針對(duì)負(fù)數(shù)存儲(chǔ)設(shè)定的,對(duì)于無符號(hào)數(shù)來說,其反碼和補(bǔ)碼都和原碼相等。

原碼:

所謂原碼,就是將數(shù)據(jù)直接翻譯為二進(jìn)制序列。

拿32位平臺(tái)舉例,最高位作為符號(hào)位,正數(shù)的符號(hào)位為0,負(fù)數(shù)的符號(hào)位為1,后面的31位稱為有效位,以不同的權(quán)重計(jì)算出不同的數(shù)字,最低位的權(quán)重為20,其次為21,以此類推。

如:

13的原碼為:00000000000000000000000000001101-3的原碼為:10000000000000000000000000000011

反碼:

反碼,顧名思義,就是將原碼的二進(jìn)制序列按位取反,但這里需要注意,并不是將所有的二進(jìn)制位都按位取反,符號(hào)位是特殊獨(dú)立出來的,他表示一個(gè)數(shù)的正負(fù),隨意取反可能會(huì)遭遇意想不到的結(jié)果。

所以反碼應(yīng)該通過原碼除符號(hào)位,其他位按位取反獲得。
(注:正數(shù)的反碼和原碼相等。)

如:

13的反碼為:00000000000000000000000000001101-3的反碼為:11111111111111111111111111111100

補(bǔ)碼:

整數(shù)在內(nèi)存中的存儲(chǔ)存的都是補(bǔ)碼,所以要通過上面的反碼求出補(bǔ)碼,補(bǔ)碼的獲取規(guī)則是原碼按位取反(除符號(hào)位)再加一。
(注:正數(shù)的補(bǔ)碼和原碼相等。)

如:

13的補(bǔ)碼為:00000000000000000000000000001101-3的補(bǔ)碼為:11111111111111111111111111111101

因?yàn)檎麛?shù)在內(nèi)存中的存儲(chǔ)形式是補(bǔ)碼,所以引出原反補(bǔ)的意義就是求出補(bǔ)碼,而補(bǔ)碼的計(jì)算公式為:補(bǔ)碼 = 原碼按位取反(除符號(hào)位)再加一

這里我們通過VS2019編譯器進(jìn)行驗(yàn)證內(nèi)存中存儲(chǔ)的是數(shù)據(jù)的補(bǔ)碼:

int main(){	int a = 13;	//原碼:00000000 00000000 00000000 00001101	//反碼:01111111 11111111 11111111 11110010	//補(bǔ)碼:01111111 11111111 11111111 11110011	int b = -3;	//原碼:10000000 00000000 00000000 00000011	//反碼:11111111 11111111 11111111 11111100	//補(bǔ)碼:11111111 11111111 11111111 11111101	return 0;}

編譯器下調(diào)試 - 內(nèi)存 - &a:


內(nèi)存中存儲(chǔ)的是:0d 00 00 00

為小端存儲(chǔ)模式,00001101轉(zhuǎn)換為十六進(jìn)制就是0d。

編譯器下調(diào)試 - 內(nèi)存 - &b:


內(nèi)存中存儲(chǔ)的是:fd ff ff ff

為小端存儲(chǔ)模式,1111 1111轉(zhuǎn)換為十六進(jìn)制就是ff,1111 1101轉(zhuǎn)換為十六進(jìn)制就是fd。

如此說來,在內(nèi)存中真的存放的就是補(bǔ)碼,所以為了弄清楚整型數(shù)據(jù)在內(nèi)存中的存儲(chǔ),必須牢牢掌握原反補(bǔ)的概念。


?截?cái)嗯c整型提升

我們知道int類型的變量所占空間大小是4個(gè)字節(jié)32個(gè)bit位(32位平臺(tái)下),而char類型的變量所占空間大小是1個(gè)字節(jié)8個(gè)bit位,那我要怎么將一個(gè)整型的數(shù)據(jù)存放在一個(gè)char類型的變量里呢?這里教大家一個(gè)很有用的辦法,那就是沒辦法,32個(gè)比特位是不可能放進(jìn)8個(gè)小格子里的,所以就會(huì)發(fā)生所謂的截?cái)?/strong>。

我們知道,一個(gè)char類型只能存放8個(gè)比特位,那如果我要將char類型的數(shù)據(jù)以%d的形式打印,也就是看做32位數(shù)據(jù)將其打印,那有要怎么做呢?再教大家一個(gè)辦法,那依然是沒辦法,所以編譯器只能對(duì)char類型的數(shù)據(jù)進(jìn)行整型提升

接下來簡單講解截?cái)嗪驼吞嵘脑怼?/p>

截?cái)?/mark>

假設(shè)我有一個(gè)32位二進(jìn)制序列:
01010011001000110001000100100011

這是一個(gè)非常大的數(shù)字:

有一個(gè)char類型的空間:

在把32位數(shù)字往里放的時(shí)候會(huì)發(fā)現(xiàn)放不下,便會(huì)發(fā)生截?cái)啵槐A舻桶宋坏臄?shù)字,其他24位數(shù)字直接舍棄,

最終存放的結(jié)果為:

這就是截?cái)嗟倪^程。

整型提升

當(dāng)我要將char類型的數(shù)據(jù)以%d的形式打印時(shí),我們知道,%d是打印有符號(hào)整型,打印的是32位0/1序列的最終結(jié)果,但我們的char類型里只存放了8位,這個(gè)時(shí)候就會(huì)發(fā)生整型提升。

整型提升規(guī)則:

  1. 如果對(duì)無符號(hào)數(shù)進(jìn)行整型提升,則在前面補(bǔ)24位0。
  2. 如果對(duì)有符號(hào)數(shù)進(jìn)行整型提升,則判斷該數(shù)在當(dāng)前的二進(jìn)制0/1序列的首元素,相當(dāng)于符號(hào)位。
    - 如果是0,則全補(bǔ)0
    - 如果是1,則全補(bǔ)1

如:

今有一8位無符號(hào)數(shù)。

unsigned char a = 148;

首先我們寫出該數(shù)的二進(jìn)制序列。

10010100 - 148

由于變量a是無符號(hào)類型的,所以不管該二進(jìn)制序列首元素是0還是1,都將全部補(bǔ)0

獲得:

00000000000000000000000010010100

最終打印的結(jié)果就是148

?整型數(shù)據(jù)存儲(chǔ)練習(xí)

對(duì)以下代碼分析輸出結(jié)果:

1.//輸出什么?int main(){	char a = -1;	signed char b = -1;		unsigned char c = -1;	printf("a=%d b=%d c=%d/n", a, b, c);	return 0;}

首先VS2019編譯器對(duì)char類型的處理為默認(rèn)認(rèn)為是有符號(hào)的char,所以變量a和變量b屬于同一類型。

先計(jì)算出-1的補(bǔ)碼。

int main(){	//-1	//原碼:10000000000000000000000000000001	//反碼:11111111111111111111111111111110	//補(bǔ)碼:11111111111111111111111111111111		char a = -1;	signed char b = -1;		unsigned char c = -1;		printf("a=%d b=%d c=%d/n", a, b, c);	return 0;}

三個(gè)變量都是char類型,所以存儲(chǔ)時(shí)都將發(fā)生截?cái)?/mark>。

int main(){	//-1	//原碼:10000000000000000000000000000001	//反碼:11111111111111111111111111111110	//補(bǔ)碼:11111111111111111111111111111111	char a = -1;	//存儲(chǔ)的補(bǔ)碼:11111111	signed char b = -1;	//存儲(chǔ)的補(bǔ)碼:11111111	unsigned char c = -1;	//存儲(chǔ)的補(bǔ)碼:11111111	printf("a=%d b=%d c=%d/n", a, b, c);	return 0;}

現(xiàn)在要將三個(gè)變量以%d形式打印,則會(huì)發(fā)生整型提升

  • 而對(duì)于變量a和變量b來說,存放的是有符號(hào)的char,根據(jù)第一個(gè)二進(jìn)制位決定提升的數(shù)為1,所以

變量a和變量b整型提升后的結(jié)果為:

11111111111111111111111111111111
  • 而對(duì)于變量c來說,它是無符號(hào)的char,直接全部補(bǔ)0,所以

變量c整型提升后的結(jié)果為:

00000000000000000000000011111111

因?yàn)樘嵘蟮腸符號(hào)位是0,所以原反補(bǔ)碼均相等。

而按%d形式打印需要將補(bǔ)碼轉(zhuǎn)化為原碼后轉(zhuǎn)化為十進(jìn)制進(jìn)行打印,

所以:

int main(){	//-1	//原碼:10000000000000000000000000000001	//反碼:11111111111111111111111111111110	//補(bǔ)碼:11111111111111111111111111111111	char a = -1;	//存儲(chǔ)的補(bǔ)碼:11111111	//提升后的補(bǔ)碼:11111111111111111111111111111111	//提升后的反碼:10000000000000000000000000000000	//提升后的原碼:10000000000000000000000000000001	signed char b = -1;	//存儲(chǔ)的補(bǔ)碼:11111111	//提升后的補(bǔ)碼:11111111111111111111111111111111	//提升后的反碼:10000000000000000000000000000000	//提升后的原碼:10000000000000000000000000000001	unsigned char c = -1;	//存儲(chǔ)的補(bǔ)碼:11111111	//提升后的補(bǔ)碼:00000000000000000000000011111111	//提升后的反碼:00000000000000000000000011111111	//提升后的原碼:00000000000000000000000011111111	printf("a=%d b=%d c=%d/n", a, b, c);	return 0;}

這么一來,打印的結(jié)果就應(yīng)該是-1 -1 255

打印結(jié)果:

  1. 下面程序輸出什么?
2.int main(){	char a = -128;	printf("%u/n", a);	return 0;}

這道題的變量a是有符號(hào)的char類型的。

首先計(jì)算出-128的原反補(bǔ)碼。

int main(){	char a = -128;	//-128	//原碼:10000000000000000000000010000000	//反碼:11111111111111111111111101111111	//補(bǔ)碼:11111111111111111111111110000000	printf("%u/n", a);	return 0;}

將01111111111111111111111110000000這樣一個(gè)二進(jìn)制序列存放進(jìn)a中將會(huì)發(fā)生截?cái)?/mark>。

截?cái)嘀骯中存放的結(jié)果為:10000000

這時(shí)以%u的形式打印,也就是以無符號(hào)整型的形式打印,要進(jìn)行整型提升,而變量a是一個(gè)有符號(hào)的char類型,第一個(gè)元素是1,所以整型提升24個(gè)1。

int main(){	char a = -128;	//-128	//原碼:10000000000000000000000010000000	//反碼:11111111111111111111111101111111	//補(bǔ)碼:11111111111111111111111110000000	//截?cái)嗟慕Y(jié)果:10000000	//整型提升后的結(jié)果:11111111111111111111111110000000	printf("%u/n", a);	return 0;}

這時(shí)要將提升之后的補(bǔ)碼轉(zhuǎn)換為原碼后以十進(jìn)制的形式進(jìn)行打印。

而%u的形式將把補(bǔ)碼中的符號(hào)位看做是有效位,所以其原反補(bǔ)都是一樣的。

int main(){	char a = -128;	//-128	//原碼:10000000000000000000000010000000	//反碼:11111111111111111111111101111111	//補(bǔ)碼:11111111111111111111111110000000	//截?cái)嗟慕Y(jié)果:10000000	//整型提升后的結(jié)果:11111111111111111111111110000000		//補(bǔ)碼:11111111111111111111111110000000	//反碼:11111111111111111111111110000000	//原碼:11111111111111111111111110000000	printf("%u/n", a);	return 0;}

而11111111111111111111111110000000的值應(yīng)該是4,294,967,168

所以輸出結(jié)果:

3.int main(){	char a = 128;	printf("%u/n", a);	return 0;}

還是一樣,先求出128的補(bǔ)碼,由于128是正數(shù),所以其原反補(bǔ)都是相同的為:

00000000000000000000000010000000

存放進(jìn)變量a中將發(fā)生整型截?cái)啵?/p>

10000000

而變量a為有符號(hào)的char類型,所以整型提升為

11111111111111111111111110000000

變量a以%u形式打印,則把符號(hào)位看成有效位,則此時(shí)原碼反碼補(bǔ)碼相同,直接進(jìn)行計(jì)算,11111111111111111111111110000000的十進(jìn)制形式為4,294,967,168

所以打印結(jié)果為:

4.int mian(){	int i = -20;	unsigned int j = 10;	//按照補(bǔ)碼的形式進(jìn)行運(yùn)算,最后格式化成為有符號(hào)整數(shù)	printf("%d/n", i + j);		return 0;}

還是先把-20和10的補(bǔ)碼計(jì)算出來,但是這里的i和j都是整型變量,所以不會(huì)發(fā)生截?cái)嗪驼吞嵘?/p>

int mian(){	int i = -20;	//-20	//原碼:10000000000000000000000000010100	//反碼:11111111111111111111111111101011	//補(bǔ)碼:11111111111111111111111111101100	unsigned int j = 10;	//10	//補(bǔ)碼:00000000000000000000000000001010	//按照補(bǔ)碼的形式進(jìn)行運(yùn)算,最后格式化成為有符號(hào)整數(shù)	printf("%d/n", i + j);		return 0;}

數(shù)據(jù)的計(jì)算是按照二進(jìn)制補(bǔ)碼的形式進(jìn)行計(jì)算的,最后的結(jié)果再根據(jù)打印要求或者存儲(chǔ)要求進(jìn)行調(diào)整更改。

計(jì)算的結(jié)果

int mian(){	int i = -20;	//-20	//原碼:10000000000000000000000000010100	//反碼:11111111111111111111111111101011	//補(bǔ)碼:11111111111111111111111111101100	unsigned int j = 10;	//10	//補(bǔ)碼:00000000000000000000000000001010	//計(jì)算:	//11111111111111111111111111101100	//00000000000000000000000000001010	//11111111111111111111111111110110 - 補(bǔ)碼相加的結(jié)果	//按照補(bǔ)碼的形式進(jìn)行運(yùn)算,最后格式化成為有符號(hào)整數(shù)	printf("%d/n", i + j);		return 0;}

要求按%d的形式打印,則將計(jì)算的結(jié)果轉(zhuǎn)化為原碼以有符號(hào)十進(jìn)制數(shù)打印。

補(bǔ)碼:11111111111111111111111111110110反碼:10000000000000000000000000001001原碼:10000000000000000000000000001010

計(jì)算結(jié)果為-10

int main(){	unsigned int i;	for (i = 9; i >= 0; i--)	{		printf("%u/n", i);	}	return 0;}

程序分析:

變量i從9開始自減到0時(shí),都可以正常進(jìn)入程序打印的值就是

9 8 7 6 5 4 3 2 1 0

在打印完0之后,變量i再自減1,變成-1,按道理來說應(yīng)該跳出循環(huán),但我們注意,這里的變量i為無符號(hào)整型,而-1的補(bǔ)碼為11111111111111111111111111111111,所以會(huì)被解析為一個(gè)特別大的正整數(shù):4294967295。


那么他也符合循環(huán)控制條件(i >= 0),所以循環(huán)會(huì)繼續(xù)4294967295次,而一直自減到0的時(shí)候,再次自減又變成-1,有被解析為4294967295,所以該程序?qū)o限循環(huán)下去。

這里博主隨便截兩張打印結(jié)果的圖供大家參考。

6.#include <           
               
                                           
                       
                 

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/122193.html

相關(guān)文章

  • C語言進(jìn)階第一問:數(shù)據(jù)內(nèi)存中是如何存儲(chǔ)?(手把手帶你深度剖析數(shù)據(jù)內(nèi)卒中存儲(chǔ),超全解析,碼住不

    摘要:在符號(hào)位中,表示正,表示負(fù)。我們知道對(duì)于整型來說,內(nèi)存中存放的是該數(shù)的補(bǔ)碼。在計(jì)算機(jī)系統(tǒng)中,數(shù)值一律用補(bǔ)碼來表示和存儲(chǔ)。表示有效數(shù)字,。規(guī)定對(duì)于位的浮點(diǎn)數(shù),最高的位是 ...

    ghnor 評(píng)論0 收藏0
  • 【C語言進(jìn)階學(xué)習(xí)】一、數(shù)據(jù)存儲(chǔ) (深度剖析數(shù)據(jù)內(nèi)存存儲(chǔ))

    摘要:的理解和區(qū)別代表有符號(hào),整數(shù)在內(nèi)存中存儲(chǔ)的二進(jìn)制位的最高位為符號(hào)位,表示負(fù)數(shù),表示正數(shù)。那接下來我們來學(xué)習(xí)數(shù)據(jù)在所開辟的內(nèi)存空間時(shí)如何存儲(chǔ)的。請(qǐng)看下面例子為什么內(nèi)存中存儲(chǔ)的是補(bǔ)碼對(duì)于整數(shù)來說數(shù)據(jù)存放內(nèi)存中其實(shí)存放的是補(bǔ)碼。 ...

    AprilJ 評(píng)論0 收藏0
  • CDN高級(jí)技術(shù)專家周哲:深度剖析短視頻分發(fā)過程中用戶體驗(yàn)優(yōu)化技術(shù)點(diǎn)

    摘要:講解從三個(gè)部分展開短視頻應(yīng)用場景阿里云短視頻解決方案阿里云對(duì)短視頻用戶體驗(yàn)的相關(guān)優(yōu)化。同時(shí),為了面對(duì)業(yè)務(wù)的突發(fā)流量,阿里云提供了超過的帶寬儲(chǔ)備,為持續(xù)增長的業(yè)務(wù)保駕護(hù)航。二播放卡頓是指在播放過程中的不流暢情況,會(huì)嚴(yán)重影響用戶體驗(yàn)。 深圳云棲大會(huì)已經(jīng)圓滿落幕,在3月29日飛天技術(shù)匯-彈性計(jì)算、網(wǎng)絡(luò)和CDN專場中,阿里云CDN高級(jí)技術(shù)專家周哲為我們帶來了《海量短視頻極速分發(fā)》的主題分享,帶...

    alphahans 評(píng)論0 收藏0
  • 深度剖析智能合約升級(jí)——inherited storage

    摘要:接上篇合約升級(jí)模式介紹筆者改寫了一個(gè)可用于實(shí)踐生產(chǎn)的升級(jí)框架,需要自取。在介紹合約升級(jí)模式中提到了一個(gè)可以解決這個(gè)問題的方法。深度理解注意為中的低階方法下文中出現(xiàn)的方法,是我在智能合約中寫的一個(gè)方法名稱,不要混淆。 接上篇:合約升級(jí)模式介紹筆者改寫了一個(gè)可用于實(shí)踐生產(chǎn)的升級(jí)框架,需要自取。https://github.com/hammewang/... 同時(shí)歡迎討論,微信xiuxiu1...

    aervon 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<