成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

再識C語言(五)

BigTomato / 1201人閱讀

摘要:注不要移動負(fù)數(shù)位標(biāo)準(zhǔn)未定義行為這種行為屬于標(biāo)準(zhǔn)未定義行為語言中并沒有規(guī)定移動負(fù)數(shù)位。按進制位與規(guī)則兩個二進制數(shù),有則為,全則為。為假的時候,打印語言中表示假,非表示真無論是正數(shù)還是負(fù)數(shù)。

C語言操作符詳解

目錄

一、算術(shù)操作符

二、移位操作符

三、位操作符

四、賦值操作符

五、單目操作符

六、關(guān)系操作符

七、邏輯操作符

八、條件操作符

九、逗號表達式

十、下標(biāo)引用、函數(shù)調(diào)用和結(jié)構(gòu)體成員操作符

?十一、表達式求值

十二、 操作符查閱表

總結(jié)


C語言中的操作符有:

算術(shù)操作符、移位操作符、位操作符、賦值操作符、單目操作符、關(guān)系操作符、邏輯操作符、

條件操作符、逗號表達式、下標(biāo)引用操作符、函數(shù)調(diào)用操作符、結(jié)構(gòu)成員訪問操作符

一、算術(shù)操作符

+(加) ?????? -(減) ?????? *(乘) ?????? /(除) ?????? %(取模)

?+(加)-(減)*(乘)與數(shù)學(xué)中的類似,這里就不過多的敘述了。

(1)% : 取模(取余)得到的是相除之后的余數(shù)

?(2)/ :除法 得到的是商

  • 當(dāng)? /(除號)兩端都是整數(shù)時,執(zhí)行的是整數(shù)除法,整數(shù)除法得到的結(jié)果是整數(shù)部分,小數(shù)部分直接舍去。
  • 兩端只要有一個浮點數(shù),執(zhí)行的就是浮點數(shù)的除法,浮點數(shù)除法默認(rèn)保留6位小數(shù)。

總結(jié):

  1. 除了 % 操作符之外,其他的幾個操作符可以作用于整數(shù)和浮點數(shù)。
  2. ?對于 /(除) 操作符如果兩個操作數(shù)都為整數(shù),執(zhí)行整數(shù)除法。而只要有浮點數(shù)執(zhí)行的就是浮點數(shù)除法。
  3. % 操作符的兩個操作數(shù)必須為整數(shù)。返回的是整除之后的余數(shù)。

二、移位操作符

<<:左移操作符

>>:右移操作符

注:移位操作符的操作數(shù)只能是整數(shù)

移位操作符移動的是整數(shù)的二進制位

先了解一下C語言中的二進制位

二進制與十進制的轉(zhuǎn)換

例:二進制數(shù):1 1 1 1 ---------> 1*2^3+1*2^2+1*2^1+1*2^0 = 15 (十進制)

??????? 二進制不好理解,可以想一想十進制的:? 1 2 3 ---------> 1*10^2+2*10^1+3*10^0 = 123

??????? 十進制:5? 轉(zhuǎn)換為二進制: 0101 ---------> 0*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 5

二進制、八進制、十進制、十六進制只是數(shù)值的表示形式

整數(shù)有三種二進制的表示形式:原碼、反碼、補碼

正整數(shù):原碼、反碼、補碼相同

負(fù)整數(shù):原碼、反碼、補碼不同,要進行計算!

正整數(shù):int a = 5;a是整型,a占4個字節(jié) -->32bit

直接將十進制數(shù)轉(zhuǎn)換成為對應(yīng)的二進制數(shù)得到的是原碼

a的原碼:00000000000000000000000000000101

a的反碼:00000000000000000000000000000101

a的補碼:00000000000000000000000000000101

最高位0表示正數(shù)

負(fù)整數(shù):int b = -5;b是整型,b占4個字節(jié) -->32bit

負(fù)數(shù)原碼、反碼、補碼的計算:

原碼:直接將十進制數(shù)轉(zhuǎn)換成為對應(yīng)的二進制數(shù)

反碼:原碼的符號位(最高位)不變,其他位按位取反

補碼:反碼+1

b的原碼:1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0? 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1

b的反碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0

b的補碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1

最高位1表示負(fù)數(shù)

整數(shù)在內(nèi)存中存儲的是補碼

可以看一下內(nèi)存中存儲是是不是補碼

使用-1來驗證

-1的原碼:1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0? 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

-1的反碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0

-1的補碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

?十六進制數(shù)使用 0 1 2 3 4 5 6 7 8 9 a b c d e f 表示

二進制 1 1 1 1 是十進制的15;十六進制的 f 是十進制的15

ff ff ff ff 寫成二進制形式:

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

由此可以知道整數(shù)在內(nèi)存中存儲的是補碼。

1、左移操作符: <<

移位規(guī)則: 左邊拋棄、右邊補0

正數(shù):

#includeint main(){	int a = 5;	//將a在內(nèi)存中存儲的二進制位向左移動兩位	int b = a << 2;	printf("%d/n", b);    printf("%d/n", a);	return 0;}

代碼分析

雖然變量a左移兩位后值發(fā)生了變化,但a的值不會發(fā)生變化,就相當(dāng)于 b = a+1,b的值發(fā)生了變化,a的值不會變。

運行結(jié)果

?負(fù)數(shù):

#includeint main(){	int b = -5;	//將b在內(nèi)存中存儲的二進制位向左移動兩位	int c = b << 2;	printf("%d/n", c);	printf("%d/n", b);	return 0;}

代碼分析

?運行結(jié)果

?2、右移操作符: >>

(1)算術(shù)右移

規(guī)則:右邊丟棄,左邊補原來的符號位

(2)邏輯右移

規(guī)則:右邊丟棄,左邊補0(如果是負(fù)數(shù),左邊補0得到的是正數(shù))

算術(shù)右移與邏輯右移取決于編譯器,C語言中并沒有規(guī)定具體使用哪種右移。我們常見的編譯器下都是算術(shù)右移。

正數(shù):

#includeint main(){	int a = 5;	//將a在內(nèi)存中存儲的二進制位向右移動1位	int b = a >> 1;	printf("%d/n", b);	printf("%d/n", a);	return 0;}

代碼分析

運行結(jié)果

負(fù)數(shù):

#includeint main(){	int a = -5;	//將a在內(nèi)存中存儲的二進制位向右移動1位	int b = a >> 1;	printf("%d/n", b);	printf("%d/n", a);	return 0;}

代碼分析

運行結(jié)果

?由代碼的運行結(jié)果得到,當(dāng)前編譯器采用的是算術(shù)右移(左邊補符號位)。

注:不要移動負(fù)數(shù)位

int a = 10;int b = a >> -2; //標(biāo)準(zhǔn)未定義行為

這種行為屬于標(biāo)準(zhǔn)未定義行為(C語言中并沒有規(guī)定移動負(fù)數(shù)位)。

三、位操作符

&:按位與??????? |:按位或??????? ^:按位異或

注:他們的操作數(shù)必須是整數(shù),操作的是整數(shù)的補碼。

1、按(2進制)位與:&

規(guī)則:兩個二進制數(shù),有0則為0,全1則為1。

#includeint main(){	int a = -3;	int b = -5;	int c = a & b;	printf("%d/n", c);	return 0;}

計算過程

?運行結(jié)果

2、按(2進制)位或:|

規(guī)則:兩個二進制數(shù),有1則為1,全0則為0。

#includeint main(){	int a = 3;	int b = -5;	int c = a | b;	printf("%d/n", c);	return 0;}

計算過程

?運行結(jié)果

3、按(2進制)位異或:^

規(guī)則:兩個二進制數(shù),相同為0,相異為1。

#includeint main(){	int a = 3;	int b = -5;	int c = a ^ b;	printf("%d/n", c);	return 0;}

計算過程

?運行結(jié)果

4、位操作符練習(xí)

不創(chuàng)建臨時變量(第三個變量),實現(xiàn)兩個數(shù)的交換。

方法一:

#includeint main(){	int a = 3;	int b = 5;	printf("交換前:a=%d b=%d/n", a, b);	a = a + b;	b = a - b;	a = a - b;	printf("交換后:a=%d b=%d/n", a, b);	return 0;}

運行結(jié)果

這種方法雖然可以實現(xiàn)不創(chuàng)建臨時變量交換兩個數(shù)的效果,但是當(dāng)兩個數(shù)加起來的結(jié)果超過了整型的范圍就會出錯,這種方法不能滿足任意兩個整數(shù)的交換。

方法二:

#includeint main(){	int a = 3;	int b = 5;	printf("交換前:a=%d b=%d/n", a, b);	a = a ^ b;	b = a ^ b;//b = a ^ b ^ b 	a = a ^ b;//a = a ^ a ^ b	printf("交換后:a=%d b=%d/n", a, b);	return 0;}

?運行結(jié)果

?這種方法可讀性太差,實際中交換兩個變量應(yīng)用最多的方法是創(chuàng)建臨時變量來進行交換。這里只是練習(xí)使用位操作符。

四、賦值操作符

1、= :賦值操作符

賦值操作符是一個很棒的操作符,他可以讓你得到一個你之前不滿意的值。也就是你可以給自己重新賦值。

	int a = 10;	a = 100; //賦值操作符

賦值操作符可以連續(xù)賦值,但是不建議這樣寫。

#includeint main(){	int a = 10;	int b = 0;	int c = 20;	a = b = c + 1;//連續(xù)賦值	printf("%d/n", a);	return 0;}

運行結(jié)果

上面的寫法等同于

    int a = 10;	int b = 0;	int c = 20;	b = c + 1;	a = b;

補充:

賦值操作符必須保證左邊是變量

  • ?左值,是可以放在等號左邊的,一般是一塊空間(變量)。
  • 右值,是可以放在等號右邊的,一般是一個值,或者是一塊空間的內(nèi)容。

2、復(fù)合賦值符

+=:加等???????? -=:減等???????? *= :乘等??????? /=:除等???????? %=:取模等

>>=:右移等??????? <<=:左移等???????? &=:按位與等???????? |=:按位或等???????? ^=:按位異或等

#includeint main(){	int a = 10;	int b = -5;	int c = 0;	a += 10;//等同于:a = a + 10;	c ^= b;//等同于:c = c ^ b;	printf("%d/n", a);	printf("%d/n", c);	return 0;}

其他運算符一樣的道理。這樣寫更加簡潔。?

五、單目操作符

3 + 5:

  • 3 是左操作數(shù)
  • + 是一個操作符
  • 5 是右操作數(shù)

+ 有兩個操作數(shù),它是雙目操作符

單目操作符只有一個操作數(shù)

?。哼壿嫹床僮??????? -:負(fù)值??????? +:正值??????? &:取地址???????

sizeof:計算操作數(shù)的類型長度(以字節(jié)為單位)

~:對一個數(shù)的二進制按位取反????? ? --:前置、后置--(減1)?????? ++:前置、后置++(加1)

*:間接訪問操作符(解引用操作符)??????? (類型):強制類型轉(zhuǎn)換

1、!:邏輯反操作

將一個表達式的結(jié)果,真變?yōu)榧?,假變?yōu)檎妗?/span>

#includeint main(){	int flag = 0;	//flag 為假的時候,打印hehe	if (!flag)	{		printf("hehe/n");	}	return 0;}

C語言中0表示假,非0表示真(無論是正數(shù)還是負(fù)數(shù))。

  • !真:表示假
  • !0:表示真,!0 的值為 1

2、? - :負(fù)值

#includeint main(){	int i = 0;	int a = -10;	int flag = 1;	for (i = 0; i < 10; i++)	{		printf("%d ", i * flag);		flag = -flag;	}	return 0;}

運行結(jié)果

?3、+:正值

這個符號沒什么用,對于正數(shù)加上+還是正數(shù),對于負(fù)數(shù)加上+還是負(fù)數(shù)。

4、&取地址

#includeint main(){	int a = 10;	&a;//& - 取地址操作符,獲取變量的地址	return 0;}

5、sizeof:計算操作數(shù)的類型長度(以字節(jié)為單位)

#includeint main(){	int a = 10;	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };	printf("%d/n", sizeof(a));	printf("%d/n", sizeof(int));	printf("%d/n", sizeof a);//因為sizeof是操作符,所以不加括號也行    //下面這種寫法不可以,sizeof在計算變量大小時才可以省略括號,    //sizeof在計算類型大小時不可以將括號省略。建議在寫的時候都加上括號。	printf("%d/n", sizeof int);//error	//計算數(shù)組的大?。?printf("%d/n", sizeof(arr));	printf("%d/n", sizeof(int [10]));//int [10] ->是數(shù)組 arr 的類型	return 0;}

?運行結(jié)果

#includevoid test1(int arr[]){	printf("%d/n", sizeof(arr));}void test2(char ch[]){	printf("%d/n", sizeof(ch));}int main(){	int arr[10] = { 0 };	char ch[10] = { 0 };	printf("%d/n", sizeof(arr));	printf("%d/n", sizeof(ch));	test1(arr);	test2(ch);	return 0;}

代碼分析

運行結(jié)果

6、~ 按(內(nèi)存中補碼的二進制)位取反

#includeint main(){	int a = 0;	int b = ~a;	printf("%d/n", b);	return 0;}

計算過程

0的補碼:00000000000000000000000000000000

按位取反(~0)后:

補碼:11111111111111111111111111111111
反碼:11111111111111111111111111111110
原碼:10000000000000000000000000000001

結(jié)果: - 1

~ 按位取反的使用:

#includeint main(){	int a = 10;	a |= (1 << 2);	printf("%d/n", a);	a &= ~(1 << 2);	printf("%d/n", a);	return 0;}

?運行結(jié)果

?7、++:前置、后置++(加1)

前置++:先++,后使用

#includeint main(){	int a = 10;	int b = ++a;	printf("a=%d b=%d/n", a, b);	return 0;}

運行結(jié)果

?后置++:先使用,再++

#includeint main(){	int a = 10;	int b = a++;//先將a的值賦給b,再++	printf("a=%d b=%d/n", a, b);	return 0;}

運行結(jié)果

#includeint main(){	int a = 10;	printf("%d/n", a++); //值為10	return 0;}
#includeint main(){	int a = 10;	printf("%d/n", ++a); //值為11	return 0;}

?8、 --:前置、后置--(減1)

前置--:先--,后使用

#includeint main(){	int a = 10;	int b = --a;//先將a的值賦給b,再++	printf("a=%d b=%d/n", a, b);	return 0;}

運行結(jié)果

??后置--:先使用,再--

#includeint main(){	int a = 10;	int b = a--;//先將a的值賦給b,再++	printf("a=%d b=%d/n", a, b);	return 0;}

運行結(jié)果

自增自減(++、--)不要整的太復(fù)雜

#includeint main(){	int a = 1;	int b = (++a) + (++a) + (++a);	printf("%d/n", b);	printf("%d/n", a);	return 0;}

?運行結(jié)果

同樣的代碼在Linux環(huán)境下使用 gcc 編譯器運行的結(jié)果

?由結(jié)果可以看出,這個代碼是一種錯誤的代碼,在不同的編譯器下運行會得到不同的結(jié)果。

?9、 *:間接訪問操作符(解引用操作符)

#includeint main(){	int a = 10;	int* pa = &a;	*pa = 20;//* ->解引用操作符(間接訪問操作符)	printf("%d/n", a);	return 0;}

?代碼分析

?運行結(jié)果

?10、(類型)強制類型轉(zhuǎn)換

#includeint main(){	int a =(int)3.14;//3.14 ->double類型	printf("%d/n", a);	return 0;}

?將double類型的數(shù)據(jù)強制類型轉(zhuǎn)換為整型后,得到是結(jié)果是整數(shù)部分,小數(shù)部分直接舍去。

運行結(jié)果

強制類型轉(zhuǎn)換不建議大量的使用,創(chuàng)建變量時盡量將類型匹配。

六、關(guān)系操作符

>:大于??????? >=:大于等于 ?????? <:小于??????? <=:小于等于??????? !=:不等于??????? ==:等于

關(guān)系操作符比較簡單,直接使用就可以了。

要注意:在編程的過程中容易將==和=不小心寫錯。==是用于測試兩個值相等,=是賦值。

七、邏輯操作符

&&:邏輯與??????? ||:邏輯或

區(qū)分邏輯操作符和按位操作符:

  • 按位與 & 和按位或 | :這兩個操作符是操作二進制位的。
  • 邏輯操作符:只關(guān)注變量值的真和假。

1、 &&:邏輯與

  • &&操作符左邊為假(0),就不會計算操作符右邊的表達式,整個表達式的結(jié)果為假。
  • 操作符左邊為真,會繼續(xù)計算操作符右邊的表達式。
  • 操作符兩邊只要有一個表達式的值為假,整個表達式的結(jié)果為假,值為0。
  • 只有兩個同時為真,整個表達式的結(jié)果才為真,值為1。

練習(xí)

#include int main(){    int i = 0, a = 0, b = 2, c = 3, d = 4;    i = a++ && ++b && d++;    printf("a = %d/nb = %d/nc = %d/nd = %d/n", a, b, c, d);    return 0;}

代碼分析

a=0,a++先返回a=0,a再自增(a的值為1)。當(dāng)a返回的值為0時就不會再計算&&后面的表達式,所以,a的值為1,b的值為2,c的值為3,d的值為4。最會輸出結(jié)果,a = 1,b = 2 ,c = 3,d = 4。

運行結(jié)果

2、||:邏輯或

  • ||邏輯或操作符左邊為真,就不會計算操作符左邊的表達式,整個表達式的結(jié)果為真。
  • 操作符左邊為假,會繼續(xù)計算操作符右邊的表達式。
  • 操作符兩邊只要有一個表達式的值為真,整個表達式的結(jié)果為真,值為1。
  • 只有兩個都為假,整個表達式的結(jié)果為假,值為0。
#include int main(){    int i = 0, a = 0, b = 2, c = 3, d = 4;    i = a++||++b||d++;    printf("a = %d/nb = %d/nc = %d/nd = %d/n", a, b, c, d);    return 0;}

?代碼分析

a=0,a++先返回a=0,a再自增(a的值為1)。當(dāng)a返回的值為0時計算 || 后面的表達式,b=2,++b先執(zhí)行b自增1,再返回自增后的結(jié)果為3。當(dāng)b=3時,表達式(++b)的結(jié)果為真,不會再計算||后的表達式。所以a的值為1,b的值為3,c的值為3,d的值為4。最會輸出結(jié)果,a = 1,b = 3 ,c = 3,d = 4。

運行結(jié)果

?總結(jié)

&&:左操作數(shù)為假,右邊不計算

||:左操作數(shù)作為真,右邊不計算

八、條件操作符

表達式1 ?? 表達式2 : 表達式3

如果表達式1的結(jié)果為真,則執(zhí)行表達式2,整個表達式的結(jié)果為表達式2執(zhí)行的結(jié)果

如果表達式1的結(jié)果為假,則執(zhí)行表達式3,整個表達式的結(jié)果為表達式3執(zhí)行的結(jié)果

#includeint main(){	int a = 10;	int b = 20;	int max = 0;	max = (a > b ? a : b);	printf("%d/n", max);	return 0;}

九、逗號表達式

表達式1,表達式2,表達式3 …… 表達式n

逗號表達式,就是由逗號隔開的多個表達式。

逗號表達式,從左向右依次執(zhí)行。整個表達式的結(jié)果是最后一個表達式的結(jié)果。

#includeint main(){	int a = 3;	int b = 5;	int c = 6;	int d = (a += 2, b = a - c, c = a + 2 * b);	printf("%d/n", d);	return 0;}

代碼分析

  • 先計算,a += 2,a = 3 + 2 = 5
  • 再計算b = a - c,b = 5 - 6 = -1
  • 再計算c = a + 2 * b,c = 5 + 2 * (-1) = 3
  • d的結(jié)果為最后一個表達式的結(jié)果,所以輸出d的值為3。

運行結(jié)果

?逗號表達式的使用

#includeint main(){	int a = 5;	int count = 0;	while (count < 10)	{		a = a+1;		count++;	}	//簡潔的寫法	while (a = a + 1, count++, count < 10)	{		;	}	return 0;}

十、下標(biāo)引用、函數(shù)調(diào)用和結(jié)構(gòu)體成員操作符

1、 [ ],下標(biāo)引用操作符

操作數(shù):數(shù)組名+元素下標(biāo)

#includeint main(){	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };	printf("%d/n", arr[7]);//[]就是下標(biāo)引用操作符,arr 和 7是操作數(shù)	return 0;}

運行結(jié)果

補充:

其實編譯器在編譯arr[7]時,是將arr[7]轉(zhuǎn)換成 *(arr+7)再對數(shù)組訪問。

*(arr+7) :arr是數(shù)組首元素的地址,arr+7就表示從數(shù)組首元素來說找到第8個元素(數(shù)組下標(biāo)是從0開始的,所以找到的是第8個元素)。

arr[7] ---> *(arr+7) --->*(7+arr) --->7[arr]

這里只是推導(dǎo)一下有這種形式,但在寫代碼的時候還是正常寫比較好。

2、 ( ) 函數(shù)調(diào)用操作符

接受一個或者多個操作數(shù):第一個操作數(shù)是函數(shù)名,剩余的操作數(shù)就是傳遞給函數(shù)的參數(shù)。

無參函數(shù),函數(shù)名就是操作數(shù),有參函數(shù),函數(shù)名和參數(shù)都是操作數(shù)。

3、訪問一個結(jié)構(gòu)的成員

  • . ? 結(jié)構(gòu)體.成員名
  • -> 結(jié)構(gòu)體指針->成員名
#includestruct Stu{	char name[20];	int age;	double score;};int main(){	struct Stu s = { "zhangsan",20,85.5 };	// . 操作符	//結(jié)構(gòu)體變量.結(jié)構(gòu)體成員	printf("%s %d %.1f/n", s.name, s.age, s.score);	// -> 操作符	struct Stu* ps = &s;	printf("%s %d %.1f/n", (*ps).name, (*ps).age, (* ps).score);	//結(jié)構(gòu)體指針->結(jié)構(gòu)體成員	printf("%s %d %.1f/n", ps->name, ps->age, ps->score);	return 0;}

運行結(jié)果

?十一、表達式求值

表達式求值的順序一部分是由操作符的優(yōu)先級和結(jié)合性決定。

有些表達式的操作數(shù)在求值的過程中可能需要轉(zhuǎn)換為其他類型。

1、隱式類型轉(zhuǎn)換

C的整型算術(shù)運算總是至少以缺省整型類型的精度來進行的。

為了獲得這個精度,表達式中的字符和短整型操作數(shù)在使用之前被轉(zhuǎn)換為普通整型,這種轉(zhuǎn)換稱為整型提升。

(1)整型提升的意義

表達式的整型運算要在CPU的相應(yīng)運算器件內(nèi)執(zhí)行,CPU內(nèi)整型運算器(ALU)的操作數(shù)的字節(jié)長度 一般就是int的字節(jié)長度,同時也是CPU的通用寄存器的長度。

因此,即使兩個char類型的相加,在CPU執(zhí)行時實際上也要先轉(zhuǎn)換為CPU內(nèi)整型操作數(shù)的標(biāo)準(zhǔn)長 度再計算。

通用CPU(general-purpose CPU)是難以直接實現(xiàn)兩個8比特字節(jié)直接相加運算(雖然機器指令 中可能有這種字節(jié)相加指令)。所以,表達式中各種長度可能小于int長度的整型值,都必須先轉(zhuǎn) 換為int或unsigned int,然后才能送入CPU去執(zhí)行運算

(2)整型提升的計算過程

整型提升是按照變量的數(shù)據(jù)類型的符號位來提升的。

#includeint main(){	char a = 5;	char b = 126;	char c = a + b;	printf("%d/n", c);	return 0;}

執(zhí)行過程

?運行結(jié)果

參與運算的數(shù)據(jù)類型是char和char計算,char和short計算,short和short計算都會發(fā)生整型提升。

整型提升的例子

(1)

#includeint main(){	char a = 0xb6;	short b = 0xb600;	int c = 0xb6000000;	if (a == 0xb6)		printf("a/n");	if (b == 0xb600)		printf("b/n");	if (c == 0xb6000000)		printf("c/n");	return 0;}

代碼分析

  • 變量 a 和 b要進行整形提升,但是變量c是整型所以不需要整形提升。
  • a和b整形提升之后就變成了負(fù)數(shù),所以表達式 a==0xb6 , b==0xb600 的結(jié)果為假。
  • c不發(fā)生整形提升,所以表達式 c==0xb6000000 的結(jié)果是真. 所程序輸出的結(jié)果是: c

運行結(jié)果

(2)

#includeint main(){	char c = 1;	printf("%u/n", sizeof(c));	printf("%u/n", sizeof(+c));	printf("%u/n", sizeof(-c));	return 0;}

代碼分析

  • 變量c只要參與表達式運算,就會發(fā)生整形提升。
  • 表達式 +c 就會發(fā)生提升,所以 sizeof(+c) 是4個字節(jié)。表達式 -c 也會發(fā)生整形提升,所以 sizeof(-c) 是4個字節(jié),但是 sizeof(c) ,就是1個字節(jié)。
  • 最后輸出的結(jié)果是:1 4 4

運行結(jié)果

補充:sizeof(),括號內(nèi)的表達式不參與運算。

??? int a = 10;
?? ?int b = 20;
?? ?a + b;?????

  • 表達式有兩個屬性:值屬性,類型屬性
  • a+b 中:30就是值屬性,int就是類型屬性
  • 當(dāng)知道類型屬性時,sizeof是通過類型屬性判斷表達式有幾個字節(jié),所以不需要計算。表達式的值。
#includeint main(){	short s = 20;	int a = 5;	printf("%d/n", sizeof(s = a + 4));	printf("%d/n", s);	return 0;}

?代碼分析

  • a是整型,a+4表達式的類型是int,將a+4放到變量s中,但是s是short類型,所以表達式的類型就變成了short類型。所以sizeof計算的是short類型字節(jié)的大小,結(jié)果是2。
  • sizeof()括號中的表達式不會真實計算,所以s的值還是20。
  • 最后輸出的結(jié)果是 2? 20

運行結(jié)果

2、算術(shù)轉(zhuǎn)換

?如果某個操作符的各個操作數(shù)屬于不同的類型,那么除非其中一個操作數(shù)的轉(zhuǎn)換為另一個操作數(shù)的類 型,否則操作就無法進行。下面的層次體系稱為尋常算術(shù)轉(zhuǎn)換

  1. long double???????
  2. double???????
  3. float???????
  4. unsigned long int???????
  5. long int???????
  6. unsigned int???????
  7. int
  • 上面這些類型之間轉(zhuǎn)換是由下往上轉(zhuǎn)換。
  • 例:int 類型的數(shù)與flaot類型的數(shù)進行計算,最終計算的結(jié)果應(yīng)該是float類型。

如果某個操作數(shù)的類型在上面這些列表中排名較低,那么首先要轉(zhuǎn)換為另外一個操作數(shù)的類型后執(zhí)行運算。
?

#includeint main(){	int a = 5;	float b = 3.14;	float r = a + b;//算術(shù)轉(zhuǎn)換	return 0;}

小于4個字節(jié)的類型之間計算是整型提升,其他類型之間計算時算術(shù)轉(zhuǎn)換。

注: 算術(shù)轉(zhuǎn)換要合理,要不然會有一些潛在的問題。

3、操作符的屬性

復(fù)雜表達式的求值有三個影響的因素。

  1. 操作符的優(yōu)先級
  2. 操作符的結(jié)合性
  3. 是否控制求值順序。

兩個相鄰的操作符取決于他們的優(yōu)先級。如果兩者的優(yōu)先級相同,取決于他們的結(jié)合性。

(1)操作符優(yōu)先級

#includeint main(){	int a = 10;	int b = 20;	int c = a + b * c;	return 0;}

乘法的優(yōu)先級高于加法,所以先計算乘法再計算加法。

(2)操作符結(jié)合性

相鄰操作符的優(yōu)先級相同的情況下,取決于結(jié)合性。

#includeint main(){	int a = 10;	int b = 20;	int c = a + b + c;	return 0;}

加法的結(jié)合性是從左向右計算。所以先計算a+b,再將a+b計算出的結(jié)果與c進行計算。

一些問題表達式有了優(yōu)先級和結(jié)合性也不能準(zhǔn)確的確定表達式的計算結(jié)果

(1)代碼1

a * b + c * d + e * f

這個表達式?jīng)]有唯一確定的計算順序

第一種:

  1. 計算a * b
  2. 計算c * d
  3. 計算e * f
  4. 計算a * b? +? c*d
  5. 計算a * b? +? c * d + e * f

第二種:

  1. 計算a * b
  2. 計算c * d
  3. 計算a * b? +? c*d
  4. 計算e * f
  5. 計算a * b? +? c * d + e * f

如果a,b,c,d,e,f 每個都是一個表達式,那么兩種計算順序得到的結(jié)果肯定不同。

由于*比+的優(yōu)先級高,只能保證,*的計算是比+早,但是優(yōu)先級并不 能決定第三個*比第一個+早執(zhí)行。

(2)代碼2

#includeint main(){	int c = 5;	c + --c;	return 0;}

?這個代碼中--的優(yōu)先級高于+,但是c的取值不確定。

  1. 加號的左操作數(shù)先準(zhǔn)備讓c=5,先計算--c,c = 4。5 + 4=9
  2. 加號的左操作數(shù)不準(zhǔn)備,先計算--c,c = 4。4 + 4 = 8

操作符的優(yōu)先級只能決定自減--的運算在+的運算的前面,但是我們并沒有辦法得知,+操作符的左操作數(shù)的獲取在右操作數(shù)之前還是之后求值,所以結(jié)果是不可預(yù)測的,是有歧義的。

(3)代碼3

#inclu           
               
                                           
                       
                 

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/124773.html

相關(guān)文章

  • JS魔法堂:再識instanceof

    摘要:一大家都知道一般就是用來檢查對象是否為類或子類的實例。中兩者均指向,因此添加到的屬性,也會出現(xiàn)在的中。四其實是建議實現(xiàn)者如采用的底層優(yōu)化手段。因為中定義函數(shù)啥都一樣,所以底層實現(xiàn)可以不再生成一個新的,從而從空間和時間上降低消耗。 一、Breif                             大家都知道instanceof一般就是用來檢查A對象是否為B類或子類的實例。那問題是...

    gself 評論0 收藏0
  • PHP擴展開發(fā)系列01 - 我要成為一名老司機

    摘要:找找出別人擴展真么寫的。這次主要說了下寫擴展要準(zhǔn)備的一些基本知識。比如不同編譯方式這個你看別的擴展源碼的時候就會注意到具體作用。后面再來慢慢學(xué)習(xí)老司機的各種姿勢。包括,函數(shù),函數(shù)參數(shù),函數(shù)返回值,對象,類,命名空間等等等。 PHP擴展開發(fā)系列01 - 我要成為一名老司機 1. 關(guān)于擴展的教程貌似挺全了,為啥還寫? 記錄下我寫擴展的歷程 自認(rèn)為會寫的更容易理解 我的宗旨就是 先用再識 ...

    30e8336b8229 評論0 收藏0
  • 分鐘殺穿指針 pointer——C語言專題

    摘要:另外,通過指針可以更便捷地操作數(shù)組。在一定意義上可以說,指針是語言的精髓。野指針成因除了未初始化還有就是越界訪問或者指針指向空間已經(jīng)釋放。所以不難知道兩個地址相減就是元素的個數(shù),這個表達式的前提是兩個指針指向同一塊空間。 ...

    MycLambert 評論0 收藏0
  • 分鐘腳踩大小端模式——C語言進階

    摘要:我們常用的結(jié)構(gòu),就是小端模式,什么則為大端模式?jīng)]學(xué)我也不知道是個啥,但還是擺出來。 目錄 傳統(tǒng)藝能?過渡區(qū)?正片開始?共用體原理?字節(jié)順序?大小端存儲?共用體判斷...

    andong777 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<