在Objective-C中,事實上與所有的程式設計語言一樣,在兩個數相加時使用加號(+),在兩個數相減時使用減號(-),在兩個數相乘時使用乘號(*),在兩個數相除時使用除號(/)。這些運算子稱為二元算術運算子,因為它們運算兩個值或項。
運算子的優先順序
你已經看到如何在Objective-C中執行簡單的運算,例如,加法。下面的程式進一步說明了減法、乘法和除法運算。在程式中執行的最後兩個運算引入了一個概念,即一個運算子比另一個運算子有更高的優先順序。事實上,Objective-C中的每一個運算子都有與之相關的優先順序。
優先順序用於確定包含多個運算子的運算式如何求值:優先順序較高的運算子首先求值。如果運算式包含優先順序相同的運算子,可按照從左至右或從右至左的方向來求值,具體按哪個方向求值取決於運算子。這就是通常所說的運算子結合性。
代碼清單4-2
//說明各種算術運算子的用法
#import <Foundation/Foundation.h>
int main (int argc, char *argv[])
{
@autoreleasepool {
int a = 100;
int b = 2;
int c = 25;
int d = 4;
int result;
result = a - b; //減法
NSLog (@"a - b = %i", result);
result = b * c; //乘法
NSLog (@"b * c = %i", result);
result = a / c; //除法
NSLog (@"a / c = %i", result);
result = a + b * c; //優先順序
NSLog (@"a + b * c = %i", result);
NSLog (@"a * b + c * d = %i", a * b + c * d);
}
return 0;
}
代碼清單4-2 輸出
a - b = 98
b * c = 50
a / c = 4
a + b * c = 150
a * b + c * d = 300
在聲明整型變數a、b、c、d及result之後,程式將a減b的結果指派給result,然後用恰當的NSLog調用來顯示它的值。
下一條語句
result = b * c;
將b的值和c的值相乘並將其結果儲存到result中。然後用NSLog調用來顯示這個乘法的結果。到目前為止,你應該很熟悉該過程了。
之後的程式語句引入了除法運算子——斜杠(/)。100除以25得到4,可用NSLog語句在a除以c之後立即顯示。
在某些電腦系統中,嘗試用一個整數除以0將導致程式異常終止或出現異常。即使程式沒有異常終止,執行這樣的除法所得的結果也毫無意義。在第6章“選擇結構”中,將看到如何在執行除法運算之前檢驗除數是否為0。如果除數為0,可採用適當的操作來避免除法運算。
運算式
a + b * c
不會產生結果2550(即102×25);相反,相應的NSLog語句顯示的結果為150。這是因為Objective-C與其他大多數程式設計語言一樣,對於運算式中多重運算或項的順序有自己的規則。通常情況下,運算式的計算按從左至右的順序執行。然而,為乘法和除法運算指定的優先順序比加法和減法的優先順序要高。因此,Objective-C認為運算式
a + b * c
等價於
a + (b * c)
(如果採用基本的代數規則,那麼該運算式的計算方式是相同的。)
如果要改變運算式中項的計算順序,可使用圓括弧。事實上,前面列出的運算式是相當合法的Objective-C運算式。這樣,可用運算式
result = a + (b * c);
替換代碼清單4-2中的運算式,也可以獲得同樣的結果。然而,如果用運算式
result = (a + b) * c;
來替換,則賦給result的值將是2550,因為要首先將a的值(100)和b的值(2)相加,然後將結果與c的值(25)相乘。圓括弧也可以嵌套,在這種情況下,運算式的計算要從最裡面的一對圓括弧依次向外進行。只要確保結束圓括弧和開始圓括弧的數目相等即可。
從代碼清單4-2中的最後一條語句可發現,對NSLog指定運算式作為參數時,無須將該運算式的結果先指派給一個變數,這種做法是完全合法的。運算式
a * b + c * d
可根據以上述規則,按照
(a * b) + (c * d)
即
(100 * 2) + (25 * 4)
來計算。
求出的結果300將傳遞給NSLog函數。
整數運算和一元負號運算子
代碼清單4-3鞏固了前面討論的內容,並引入了整數運算的概念。
代碼清單4-3
//更多的算術運算式
#import <Foundation/Foundation.h>
int main (int argc, char *argv[])
{
@autoreleasepool {
int a = 25;
int b = 2;
float c = 25.0;
float d = 2.0;
NSLog (@"6 + a / 5 * b = %i", 6 + a / 5 * b);
NSLog (@"a / b * b = %i", a / b * b);
NSLog (@"c / d * d = %f", c / d * d);
NSLog (@"-a = %i", -a);
}
return 0;
}
代碼清單4-3 輸出
6 + a / 5 * b = 16
a / b * b = 24
c / d * d = 25.000000
-a = -25
前3條語句中,在int和a、b及result的聲明之間插入了額外的空格,以便對齊每個變數的聲明,使用這種方法書寫語句可使程式更容易閱讀。還可以注意到,在迄今出現的每個程式中,每個運算子前後都有空格。這種做法同樣不是必需的,僅僅是出於美觀上的考慮。一般來說,在允許單個空格的任何位置都可以插入額外的空格。如果能使程式更容易閱讀,輸入空格鍵的操作還是值得做的。
在代碼清單4-3中,第一個NSLog調用中的運算式鞏固了運算子優先順序的概念。該運算式的計算按以下順序執行:
(1)因為除法的優先順序比加法高,所以先將a的值(25)除以5。該運算將給出中間結果5。
(2)因為乘法的優先順序也高於加法,所以隨後中間結果(5)將乘以2(即b的值),並獲得新的中間結果(10)。
(3)最後計算6加10,並得出最終結果(16)。
第二條NSLog語句引入了一種新誤解。你希望a除以b,再乘以b的操作返回a(已經設定為25)。但此操作並不會產生這一結果,在輸出顯示器上顯示的是24。難道電腦在某個地方迷失了方向?如果這樣就太不幸了。其實該問題的實際情況是,這個運算式是採用整數運算來求值的。
如果回頭看一下變數a和b的聲明,你會想起它們都是作為int型別宣告的。當包含兩個整數的運算式求值時,Objective-C系統都將使用整數運算來執行這個操作。在這種情況下,數位所有小數部分將丟失。因此,計算a除以b,即25除以2時,得到的中間結果是12,而不是期望的12.5。這個中間結果乘以2,就得到最終結果24。這樣,就解釋了出現“丟失”數位情況。
在代碼清單4-3的倒數第二個NSLog語句中看到,如果用浮點值代替整數來執行同樣的運算,就會獲得期望的結果。
決定使用float變數還是int變數應該基於變數的使用目的。如果無須使用任何小數位,就可以使用整型變數。這將使程式更加高效,換言之,它可以在大多數電腦上更快速地執行。另一方面,如果需要精確到小數位,那就很清楚應該選擇什麼。此時,唯一需要回答的問題是使用float還是double。對此問題的回答取決於使用資料所需的精度以及它們的量級。
在最後一條NSLog語句中,使用了一元負號運算子對變數a的值取負。這個一元運算子是用於單個值的運算子,而二元運算子作用於兩個值。負號實際上扮演了一個雙重角色;作為二元運算子,它執行兩個數相減的操作;作為一元(或單目)運算子,它對一個值取負。
與其他算術運算子相比,一元負號運算子具有更高的優先順序,但一元正號運算子(+)除外,一元正號運算子和算術運算子的優先順序相同。因此,運算式
c = -a * b;
將執行-a乘以b。
本文節選自《Objective-C程式設計(第4版)》
電子工業出版社出版
[美]Stephen G. Kochan(斯蒂芬·G·科昌)著
林冀 範俊朱奕欣譯