C語(yǔ)言操作符進(jìn)階教程(表達(dá)式求值隱式類(lèi)型轉(zhuǎn)換方法)
結(jié)構(gòu)體
結(jié)構(gòu)體變量的聲明需要在主函數(shù)之上或者主函數(shù)中聲明,如果在主函數(shù)之下則會(huì)報(bào)錯(cuò),而且c語(yǔ)言中的結(jié)構(gòu)體不能直接進(jìn)行強(qiáng)制轉(zhuǎn)換,只有結(jié)構(gòu)體指針才能進(jìn)行強(qiáng)制轉(zhuǎn)換。
涉及結(jié)構(gòu)體的操作符這里講兩個(gè):. (結(jié)構(gòu)體訪問(wèn)操作符)-> ()
首先寫(xiě)一段代碼:
int main()
{
struct Stu s = {"me",19,60};
prinft("%s %d %lf",s.who,s.age,s.weight)
return 0;
}
這就是個(gè)結(jié)構(gòu)體訪問(wèn),這里的結(jié)構(gòu)是:結(jié)構(gòu)體變量 . 結(jié)構(gòu)體成員,箭頭怎么用呢?當(dāng)我有一個(gè)結(jié)構(gòu)體指針:
struct Stu * ps = &s;
printf("%s %d %lf\n"),(*ps).name,(*ps).age,(*ps).score);
return 0;
這里我是對(duì) ps 解引用一下,找到他所指向的對(duì)象,其實(shí)和上面第一組代碼的結(jié)果是一樣的;但是,橫看豎看都覺(jué)得有點(diǎn)啰嗦,我們把格局打開(kāi):
printf("%s %d %lf\n",ps->name,ps->age,ps->score);
return 0;
這樣是不是看著要清爽許多?->操作符的基本語(yǔ)法是:結(jié)構(gòu)體指針 -> 結(jié)構(gòu)體成員
表達(dá)式求值
我們?cè)诮佑|那么多的操作符后,就可以應(yīng)用來(lái)進(jìn)行計(jì)算,表達(dá)式求值的順序一部分是由操作符的優(yōu)先級(jí)和綜合性決定。同樣,有些表達(dá)式的操作數(shù)在求值過(guò)程可能需要轉(zhuǎn)換成其他類(lèi)型。
隱式類(lèi)型轉(zhuǎn)換
C語(yǔ)言的整型算術(shù)運(yùn)算總是至少以缺省整型類(lèi)型的精度來(lái)進(jìn)行的。為了獲取這個(gè)精度,表達(dá)式中的字符和短整型操作數(shù)在使用之前被轉(zhuǎn)換為普通整型,這種轉(zhuǎn)換被稱(chēng)為整型提升
意義:
表達(dá)式的整型運(yùn)算要在CPU的相應(yīng)運(yùn)算器件內(nèi)執(zhí)行,CPU內(nèi)整型運(yùn)算器(ALU)的操作數(shù)的字節(jié)長(zhǎng)度一般就是int的字節(jié)長(zhǎng)度,同時(shí)也是CPU的通用寄存器的長(zhǎng)度。因此,即使兩個(gè)char類(lèi)型的相加,在CPU執(zhí)行時(shí)實(shí)際上也要先轉(zhuǎn)換為CPU內(nèi)整型操作數(shù)的標(biāo)準(zhǔn)長(zhǎng)度。通用CPU(general-purpose CPU)是難以直接實(shí)現(xiàn)兩個(gè)8比特字節(jié)直接相加運(yùn)算(雖然機(jī)器指令中可能有這種字節(jié)相加指令)。所以,表達(dá)式中各種長(zhǎng)度可能小于int長(zhǎng)度的整型值,都必須先轉(zhuǎn)換為int或unsigned int,然后才能送入CPU去執(zhí)行運(yùn)算。
我們用一段代碼代入一下:
int main()
{
char a = 5;
char b = 126;
char = a+b;
printf("%d\n",c);
return 0;
}
這里的一個(gè)表達(dá)式:a+b, 其中a和b的類(lèi)型都是 char 類(lèi)型,按照定義來(lái)看,也就是這段代碼的運(yùn)行遠(yuǎn)比我們想象的復(fù)雜 ,我們知道 sizeof(char),sizeof(short)的大小肯定是小于 int 類(lèi)型的,所以我們計(jì)算時(shí)就要把char,short提升成 int(unsigned int)類(lèi)型,再執(zhí)行運(yùn)算。
方法
整型提升是按照變量的數(shù)據(jù)類(lèi)型的符號(hào)位來(lái)提升的,char x = -1 中,x的二進(jìn)制位(補(bǔ)碼)只有8個(gè)比特位,char為有符號(hào)的char所以整型提升時(shí),高位補(bǔ)充符號(hào)位,即為1;無(wú)符號(hào)整型提升,高位補(bǔ)0。
就拿剛剛的代碼進(jìn)行剖析:
int main()
{
char a = 5;
//5 = 0000……0101(32位)
//char類(lèi)型一個(gè)字節(jié)8個(gè)比特位,就只能從5的二進(jìn)制數(shù)中獲取8位
//即a=00000101
//這一步叫截?cái)?
char b = 126;
//126 = 0000……01111110(32位)
//b = 01111110
char = a+b;
//當(dāng)a,b相加時(shí)整型提升
//111111111……0000011
//111111111……0000010
//100000000……1111101(符號(hào)位不變,其他位按位取反)=-125
printf("%d\n",c);//
return 0;
下面這個(gè)代碼就可以證明整型提升的存在:
int main()
{
char c= 1;
printf("%u\n",sizeof(c));
printf("%u\n",sizeof(+c));
printf("%u\n",sizeof(-c));
return 0;
}

從運(yùn)行結(jié)果來(lái)看,為什么會(huì)是 4 呢?其實(shí)就是因?yàn)樗麉⑴c了運(yùn)算,進(jìn)行了整型提升,變成了int類(lèi)型。
算術(shù)轉(zhuǎn)換
我們?cè)趧倓傉劦氖?char 和 short 的計(jì)算,那如果是int 和 long ,int 和long long,int 和 float 以及 double計(jì)算呢?他們發(fā)生的就是算術(shù)轉(zhuǎn)換。總的來(lái)說(shuō)就是4字節(jié)以下的屬于整型提升,大于4的屬于算術(shù)轉(zhuǎn)換。
是指如果其中操作符的各個(gè)操作數(shù)為不同類(lèi)型,除非其中一個(gè)轉(zhuǎn)換成另一個(gè)類(lèi)型,否則無(wú)法進(jìn)行操作。下面層次的系統(tǒng)稱(chēng)為尋常算術(shù)轉(zhuǎn)換
char
short
int
long
long long
float
double
short a = 10;
int b = 5;
prinft("%d\n",sizeof(a+b+1));
printf 結(jié)果是 2 ,是因?yàn)閟hort只有兩個(gè)字節(jié)大小,在表達(dá)式中 short a 當(dāng)家做主,不管放什么進(jìn)來(lái)都是short,但是,sizeof 內(nèi)部多表達(dá)式其實(shí)不會(huì)真實(shí)計(jì)算,我們寫(xiě)文件通常是 test.c,要生成 .exe 的可執(zhí)行文件三步走:編譯,鏈接,運(yùn)行。在表達(dá)式進(jìn)去在編譯的時(shí)候就變成 2 了,根本到不了運(yùn)行。
如果某個(gè)數(shù)類(lèi)型在上表中排名較低,那會(huì)首先轉(zhuǎn)換到另一個(gè)操作數(shù)的類(lèi)型后執(zhí)行運(yùn)算。
PS.算術(shù)轉(zhuǎn)換要合理,不然會(huì)出現(xiàn)潛在問(wèn)題。
比如把 float 類(lèi)型變成 int 類(lèi)型就會(huì)造成精度丟失。
操作符屬性
復(fù)雜表達(dá)式的求值有三個(gè)影響因素:
1.操作符優(yōu)先級(jí)
2.操作符結(jié)合性
3.是否控制求值順序
首先優(yōu)先級(jí)是在求值時(shí),相鄰兩個(gè)操作符先執(zhí)行哪個(gè)的問(wèn)題,當(dāng)優(yōu)先級(jí)相同時(shí),取決于他們的結(jié)合性。
什么是結(jié)合性?舉個(gè)栗子: a = b = c;
b的左右兩側(cè)都為 = 號(hào),而 = 具有右結(jié)合性,故應(yīng)該由右向左計(jì)算,即:a = (b = c),諸如此類(lèi),有表如下(片段):

還有一些關(guān)于優(yōu)先級(jí)的常見(jiàn)錯(cuò)誤值得注意一下:

有了上面這些屬性是不是任意給一個(gè)表達(dá)式就可以確定一個(gè)唯一的計(jì)算路徑呢?答案是:NO!比如一些問(wèn)題表達(dá)式:
a*b+c*d+e*f; a + --a;
第一個(gè)可能第一感覺(jué)就是三個(gè)部分依次先乘后加給扒拉出來(lái),這就想的太簡(jiǎn)單了,如果我把 abcdef 換成表達(dá)式,那就可能會(huì)相互影響,存在潛在問(wèn)題。
第二個(gè)就不是計(jì)算順序的問(wèn)題了,是取值時(shí)機(jī)的問(wèn)題,左右操作數(shù)相互關(guān)聯(lián)時(shí),計(jì)算路徑可能不唯一。
諸君謹(jǐn)記,以上代碼誰(shuí)寫(xiě)誰(shuí)特么就是豬隊(duì)友,謹(jǐn)記!
以上就是C語(yǔ)言操作符進(jìn)階教程(表達(dá)式求值隱式類(lèi)型轉(zhuǎn)換方法)的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言操作符表達(dá)式求值隱式類(lèi)型轉(zhuǎn)換的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深入探索C++ string的底層實(shí)現(xiàn)
C語(yǔ)言中的字符串是以字符數(shù)組的形式存儲(chǔ)的,每個(gè)字符占用一個(gè)字節(jié)的內(nèi)存空間,本文我們將和大家一起深入探討一下string的底層實(shí)現(xiàn),感興趣的小伙伴快來(lái)和小編一起吧2023-08-08
C語(yǔ)言超詳細(xì)講解棧與隊(duì)列實(shí)現(xiàn)實(shí)例
棧和隊(duì)列,嚴(yán)格意義上來(lái)說(shuō),也屬于線性表,因?yàn)樗鼈円捕加糜诖鎯?chǔ)邏輯關(guān)系為?"一對(duì)一"?的數(shù)據(jù),但由于它們比較特殊,因此將其單獨(dú)作為一章,做重點(diǎn)講解2022-03-03
c++11?實(shí)現(xiàn)枚舉值到枚舉名的轉(zhuǎn)換問(wèn)題
這篇文章主要介紹了c++11?實(shí)現(xiàn)枚舉值到枚舉名的轉(zhuǎn)換,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
詳解C++中的內(nèi)存同步模式(memory order)
這篇文章主要介紹了C++中的內(nèi)存同步模式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04

