C和指針學習筆記四:操作符和表達式

一、操作符

包括:算術操作符,移位操作符,位操作符,賦值操作符,單目操作符,關系操作符,邏輯操作符,條件操作符,下標引用,函數調用,結構體成員調用。

1、算術操作符

加、減、乘、除、取模(%)
取模的兩個操作數只能是整型值。

2、移位操作符

左移位:<< 最左邊幾位丟棄,最右邊幾位補0;
右移位:>> (1)邏輯移位:最右邊幾位丟棄,左邊補0;
(2)算術移位:最右邊幾位丟棄,左邊符號位為0,則全移入0,為1則全移入1。

標準規定無符號數都執行邏輯移位,而有符號數執行的是邏輯移位還是算術移位由編譯器決定,若移位的位數超過操作數的位數,則具體情況由編譯器決定。

所以出現有符號數移位操作的程序是不可移植的。

3、位操作符

& | ^ (與,或,異或)
通常用于位操作,修改變量指定位的值。
舉例:
value的第bit_number位置1:
value |= 1 << bit_number;
value的第bit_number位置0:
value &= ~ (1 << bit_number);
測試指定位是否為1,為1則表達式非0:
value &= 1 << bit_number;

4、賦值操作符

賦值是表達式的一種,而不是某種類型的語句,所以只要允許出現表達式的地方都可以進行賦值。

舉例:
a = x = y + 3;
a和x被賦的值并不是同一個值
若x的長度不夠,則x被賦予的y+3值會被截短,再存儲于x中,之后這個被截短的值再被賦予到a中。

復合賦值符:+=,-=,|=等等,多使用可以使代碼更簡潔。

5、單目操作符

!; ++; -- ; + ;-; ~ ;& ;* ;sizeof ; (類型)

  • sizeof():判斷操作數的類型長度,以字節為單位。
    sizeof (int):必須加括號;
    sizeof x:可以不加括號;

舉例:
16位機器中:int arry[10];
則sizeof(arry)=20
sizeof(arry[0])=2
sizeof(arry)/sizeof(arry[0])=10,即數組中元素的個數。

sizeof(a = b + 3):sizeof可以判斷表達式的長度,此時不需要求表達式的值,所以a并沒有被賦值;表達式返回a的大小。

  • (類型):強制類型轉換(cast),具有很高的優先級,所以注意:把強制類型轉換放在表達式的前面只會改變第一個項目的類型,要操作整個表達式的話,就要加括號。
    float(a):獲得a對應的浮點數值。

  • 增值++和減值--操作符。
    前綴操作符在變量被使用之前改變變量的值;
    后綴操作符在變量被使用之后改變變量的值。

舉例:
c = ++a; d=a++;
其中,c得到a增加之前的值,d得到a增加之后的值。

前綴和后綴形式的增值操作都復制了一份變量值的拷貝,用于周圍表達式的值是這份拷貝來的值(賦值表達式);
前綴形式,在變量值增加之后復制,后綴形式,在變量值增加之前復制。
因此這些操作符的結果不是被他們修改的變量,而是變量值的拷貝。
++a = 10;
這條語句時錯誤的,++a的結果是變量值的拷貝,不是變量a本身,因此無法向一個值進行賦值。

6、關系操作符

>;>=;<;<=;!=;==

關系操作符的結果是一個整型值,而不是布爾值,可以將結果賦值給整型變量。(C語言中沒有布爾類型,所以用整數來代替,非0位真,0為假)

7、邏輯操作符

邏輯與&&,邏輯或||,都會控制表達式的順序執行:
從左到右依次執行,&&若左操作數為假,則后續右操作數不再求值,整個表達式為假,||邏輯或同理。這個行為被稱為“短路求值”(short-circuited evaluation)。

舉例:
if(a<b && c>d)
if(a<b & c>d)

if(a && b)
if(a & b)
第一組語句的結果一樣,因為關系操作符的結果只能是0或1,而第二組語句結果不一樣,因為若a,b非0,則第一個一定為真,而a,b按位與的值并不一定非0,所以不一定為真。

8、條件操作符

expression1 ? expression2 : expression3
會控制子表達式的求值順序,expression2和expression3只會執行其中一個。
b = a > 5 ? 3 : -20;
a > 5則b = 3,否則b = -20。
條件操作符的作用有時類似于if,else,且比它更簡潔。

9、逗號操作符

expression1,expression2,expression3,......,expressionN
將多個表達式用逗號分開,并從左到右依次執行,整個表達式的值為最后那個表達式的值。

while(a = get_value(), count_value( a ), a>0)
{
  expression;
}

因為依次執行,所以用在循環語句的測試表達式中時,獲得下一個測試值語句只出現一次,修改時只需要在一個地方修改,方便程序的維護。

二、表達式求值

  • 表達式的求值順序由所包含操作符的優先級和結合性決定;
  • 求值過程中的類型轉換。

1、隱式類型轉換(implicit conversion)

  • 發生的情況:

    • 算術表達式或邏輯表達式的操作數類型不相同時;(執行常用算術轉換,即usual arithmetic conversion)
    • 操作符兩邊的變量類型不相同時;
    • 函數調用時,實參與形參不匹配時;
    • return語句中表達式類型和函數返回值類型不匹配時。
  • 隱式轉換規則
    long double
    double
    float
    unsigned long int
    long int
    unsigned int
    int
    排名較低的操作數首先轉換為另一個操作數的類型,即低精度數像高精度數轉換。
    但是,在32位機器上,int類型和long字長相同,這時unsigned int的精度就比long精度高。

  • 整型運算符的精度至少是缺省整型類型,則運算過程中,字符型和短整型在使用之前被轉換成普通整型,這種轉換過程被稱為整型提升(integral promotion)。
    提升精度往往無害,但降低精度可能會導致問題,低精度類型可能不夠大,不能容納高精度的完整數據。

(1)算術轉換

舉例:

char a,b,c;
  statement;
  a = b + c;

首先,b和c的值被提升為整型,然后,執行加法運算,最后,將結果截短后賦值并存儲于a中。

當然,也可以使用強制類型轉換執行顯示轉換(explicit conversion):(int)a = b + c;

(2)顯示轉換

舉例:

int a = 5000;
int b = 25;
long c = a * b;
  • 在32位機器上,int和long int都是32位,這段代碼運行起來沒有問題;但在16位機器上,int是16位,long是32位,a*b的值應該是int型,但由于數據類型不夠大(max = 2^16 - 1 = 65535),所以發生溢出,c會被賦一個無意義的值,因此需要進行強制類型轉換:
    long c = (long)a*b;

  • 注意:long c = (long)(a*b);是錯誤的,因為溢出在強制轉換之前就已經發生了,所以這樣做不會有任何改變。

  • 數據溢出:

    • 有符號數的數據溢出是未定義的;
    • 無符號數的數據溢出:溢出后的數以2^(8*sizeof(type))作模運算。比如用unsigned char型變量存儲258,其實存進去的是258-2^8=2。

(3)操作符兩邊表達式的轉換

舉例:

unsigned int a = 6;
int b = -20;
int c = (a + b) > 6 ? 1 : 2;

在加法運算中a和b類型不一致,會發生隱式轉換,將int型轉換為unsigned int型,b=-20轉換為無符號數會變成一個很大的整數,因為無符號負數轉換為的正數是用負數的補碼所表示的,正數的源碼,反碼,和補碼相同。所以,程序輸出1,而不是2。

舉例:

if(strlen(arry) < 10)
if(strlen(arry) - 10 < 0)

這兩條語句不等價,因為strlen函數返回值是unsigned int型,兩個無符號數運算所得的結果仍為無符號數,而無符號數肯定大于0。所以,要盡量避免使用第二個表達式。

2、操作符的優先級

表達式的運算規則:
兩個相鄰操作符的執行順序由他們的優先級決定,若優先級相同,則由他們的結合性決定。
結合性:當多個相同優先級的運算符出現在表達式中時,先執行左邊的叫具有左結合性,先執行右邊的叫具有右結合性。

  • 舉例:

a*b + c*d + e*f

相鄰的加法和乘法運算符中,乘法運算符先執行;兩個加法運算,根據加法的左結合性,是左邊的加法運算先執行。但對于哪個乘法運算先執行,以及是否在所有乘法執行完后再執行加法運算,這些都由編譯器決定,所以表達式就會有多種執行順序。

c + --c

相鄰的+和--操作符是--先執行,但對于表達式c和--c并不知道哪個先執行,又因為--c具有副作用,所以這兩個表達式的執行順序會對結果有影響。

  • 編譯器只要不違背優先級和結合性規則,就可以任意決定復雜表達式的取值順序。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容