???樊梓慕:個(gè)人主頁
???個(gè)人專欄:《C語言》《數(shù)據(jù)結(jié)構(gòu)》《藍(lán)橋杯試題》
??每一個(gè)不曾起舞的日子,都是對(duì)生命的辜負(fù)。
目錄
前言:
一、隱式類型轉(zhuǎn)換
(一)整型提升的意義
(二)如何進(jìn)行整型提升呢?
二、算數(shù)轉(zhuǎn)換
三、操作符的屬性
(一)操作符優(yōu)先級(jí)匯總
(二)一些問題表達(dá)式
前言:
本篇文章匯總了在進(jìn)行表達(dá)式求值時(shí)一些容易出現(xiàn)錯(cuò)誤的點(diǎn),介紹整型提升的相關(guān)內(nèi)容,并提供操作符優(yōu)先級(jí)匯總表格供大家參考,希望大家多多支持博主創(chuàng)作,博主會(huì)持續(xù)帶來更多優(yōu)質(zhì)內(nèi)容??
=========================================================================
GITEE相關(guān)代碼:??fanfei_c的倉庫??
=========================================================================
一、隱式類型轉(zhuǎn)換
假如有這樣一段代碼:
char a, b, c;
...
a = b + c;
?計(jì)算機(jī)是以什么邏輯來進(jìn)行計(jì)算的呢?
實(shí)際上,C的整型算術(shù)運(yùn)算總是至少以缺省(默認(rèn))整型類型的精度來進(jìn)行的。
為了獲得這個(gè)精度,表達(dá)式中的字符(char)和短整型操作數(shù)(short)在使用之前被轉(zhuǎn)換為普通整型(int),這種轉(zhuǎn)換稱為整型提升。
(一)整型提升的意義
- 表達(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類型的相加,在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)算。
所以上面的代碼邏輯為:b和c的值被提升為普通整型,然后再執(zhí)行加法運(yùn)算。
加法運(yùn)算完成之后,結(jié)果將被截?cái)?,然后再存?chǔ)于a中。
(二)如何進(jìn)行整型提升呢?
整形提升是按照變量的數(shù)據(jù)類型的符號(hào)位來提升的。
- 負(fù)數(shù)的整形提升
char c1 = -1;
變量c1的二進(jìn)制位(補(bǔ)碼)中只有8個(gè)比特位:
1111111
因?yàn)?char 為有符號(hào)的 char
所以整形提升的時(shí)候,高位補(bǔ)充符號(hào)位,即為1
提升之后的結(jié)果是:
11111111111111111111111111111111
- 正數(shù)的整形提升
char c2 = 1;
變量c2的二進(jìn)制位(補(bǔ)碼)中只有8個(gè)比特位:
00000001
因?yàn)?char 為有符號(hào)的 char
所以整形提升的時(shí)候,高位補(bǔ)充符號(hào)位,即為0
提升之后的結(jié)果是:
00000000000000000000000000000001
- 無符號(hào)整形提升,高位補(bǔ)0
舉個(gè)栗子??:
//實(shí)例1
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
printf("a");
if (b == 0xb600)
printf("b");
if (c == 0xb6000000)
printf("c");
return 0;
}
答案:c
分析:實(shí)例1中的a,b要進(jìn)行整形提升,但是c不需要整形提升。
a,b整形提升之后,變成了負(fù)數(shù),所以表達(dá)式 a==0xb6,b==0xb600 的結(jié)果是假,但是c不發(fā)生整形提升,則表達(dá)式 c==0xb6000000 的結(jié)果是真。
//實(shí)例2
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));
return 0;
}
答案:1 4 4?
分析:實(shí)例2中的c只要參與表達(dá)式運(yùn)算,就會(huì)發(fā)生整形提升,表達(dá)式 +c ,就會(huì)發(fā)生提升,所以 sizeof(+c) 是4個(gè)字節(jié)。表達(dá)式 -c 也會(huì)發(fā)生整形提升,所以 sizeof(-c) 是4個(gè)字節(jié),但是 sizeof(c) ,就是1個(gè)字節(jié)。
二、算數(shù)轉(zhuǎn)換
那么如果表達(dá)式的各個(gè)操作數(shù)屬于不同的類型時(shí),又該如何處理呢?
此時(shí)就需要將其中一個(gè)操作數(shù)轉(zhuǎn)換為另一個(gè)操作數(shù)的類型,否則就無法計(jì)算,下面給出操作數(shù)類型轉(zhuǎn)換的優(yōu)先級(jí),該層次體系成為尋常算數(shù)轉(zhuǎn)換。
?如果某個(gè)操作數(shù)的類型在上面這個(gè)列表中排名較低,那么首先要轉(zhuǎn)換為另外一個(gè)操作數(shù)的類型后執(zhí)行運(yùn)算。
警告:
但是算術(shù)轉(zhuǎn)換要合理,要不然會(huì)有一些潛在的問題,如精度丟失:
float f = 3.14;
int num = f;//隱式轉(zhuǎn)換,會(huì)有精度丟失
三、操作符的屬性
復(fù)雜表達(dá)式的求值有三個(gè)影響的因素:
- 操作符的優(yōu)先級(jí)
- 操作符的結(jié)合性
- 是否控制求值順序
兩個(gè)相鄰的操作符先執(zhí)行哪個(gè)?取決于他們的優(yōu)先級(jí)。
如果兩者的優(yōu)先級(jí)相同,取決于他們的結(jié)合性。
(一)操作符優(yōu)先級(jí)匯總
(二)一些問題表達(dá)式
//表達(dá)式的求值部分由操作符的優(yōu)先級(jí)決定。
//代碼1
a* b + c * d + e * f
分析:代碼在計(jì)算的時(shí)候,由于*比+的優(yōu)先級(jí)高,只能保證,*的計(jì)算是比+早,但是優(yōu)先級(jí)并不
能決定第三個(gè)*比第一個(gè)+早執(zhí)行。
所以表達(dá)式的計(jì)算機(jī)順序就可能是:
a* b
c* d
a* b + c * d
e * f
a * b + c * d + e * f
或者:
a * b
c * d
e * f
a * b + c * d
a * b + c * d + e * f
//代碼2
c + --c;
?分析:同上,操作符的優(yōu)先級(jí)只能決定自減--的運(yùn)算在+的運(yùn)算的前面,但是我們并沒有辦法得
知,+操作符的左操作數(shù)的獲取在右操作數(shù)之前還是之后求值,所以結(jié)果是不可預(yù)測(cè)的,是有歧義
的。
//代碼3-非法表達(dá)式
int main()
{
int i = 10;
i = i-- - --i * (i = -3) * i++ + ++i;
printf("i = %d\n", i);
return 0;
}
分析:同上,代碼3有歧義,此時(shí)程序運(yùn)算的結(jié)果就取決于編譯器了。
如下圖:
//代碼4
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - fun() * fun();
printf("%d\n", answer);//輸出多少?
return 0;
}
分析:?answer = fun() - fun() * fun(); 中我們只能通過操作符的優(yōu)先級(jí)得知:先算乘法,
再算減法。但是函數(shù)的調(diào)用先后順序無法通過操作符的優(yōu)先級(jí)確定。
//代碼5
#include <stdio.h>
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret);
printf("%d\n", i);
return 0;
}
分析:這段代碼中的第一個(gè) + 在執(zhí)行的時(shí)候,第三個(gè)++是否執(zhí)行,這個(gè)是不確定的,因?yàn)橐揽坎僮鞣膬?yōu)先級(jí)和結(jié)合性是無法決定第一個(gè) + 和第三個(gè)前置 ++ 的先后順序。
經(jīng)過上面的例子,我們可以得出結(jié)論:
我們寫出的表達(dá)式如果不能通過操作符的屬性確定唯一的計(jì)算路徑,那這個(gè)表達(dá)式就是存在問題的,此時(shí)的結(jié)果取決于該編譯器是如何編譯的。文章來源:http://www.zghlxwxcb.cn/news/detail-600703.html
本篇文章的內(nèi)容就到這里,為了防止大家以后再遇到類似表達(dá)式求值問題時(shí)出錯(cuò),大家可以收藏本篇文章隨時(shí)查閱操作符優(yōu)先級(jí)與類型轉(zhuǎn)換相關(guān)內(nèi)容??文章來源地址http://www.zghlxwxcb.cn/news/detail-600703.html
到了這里,關(guān)于【C語言】表達(dá)式求值相關(guān)問題匯總—>隱式類型轉(zhuǎn)換(整型提升)、算數(shù)轉(zhuǎn)換與操作符優(yōu)先級(jí)匯總(收藏查閱)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!