官术网_书友最值得收藏!

第3章 運算符和表達式

即使有了變量和常量,也不能迚行日常程序處理,還必須用某種方式來將變量、常量的關系表示出來,此時運算符和表達式便應運而生。通過專用的運算符和表達式,可以實現(xiàn)對變量和常量的處理,以實現(xiàn)項目的需求。這樣就可以對變量和常量迚行必要的運算處理,來實現(xiàn)特定的功能。本章將詳細介紹Objective-C語言中運算符和表達式的基本知識,為讀者后面的學習打下堅實的基礎。

3.1 運算符的種類

知識點講解:光盤:視頻\知識點\第3章\運算符的種類.mp4

運算符可以算作是一個媒介,是一個命令編譯器對一個或多個操作對象執(zhí)行某種運算的符號。而表達式是由運算符、常量和變量構成的式子。Objective-C語言中運算符和表達式數(shù)量之多,在高級語言中是少見的。正是這些豐富的運算符和表達式,使得Objective-C語言的功能變得十分完善,這也是Objective-C語言的主要特點之一。

在Objective-C語言中,可以將運算符分為以下7大類。

(1)算術運算符:用于各類數(shù)值運算,包括加(+)、減(-)、乘(*)、除(/)、求余(或稱模運算,%)、自增(++)、自減(- -)共7種。

(2)比較運算符:用于比較運算,包括大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)和不等于(! =)6種。

(3)邏輯運算符:用于邏輯運算,包括與(&&)、或(||)、非(! )3種。

(4)位操作運算符:參與運算的量按二迚制位迚行運算,包括按位與(&)、按位或(|)、按位非(~)、按位異或(^)、左移(<<)、右移(>>)共6種。

(5)賦值運算符:用于賦值運算,分為簡單賦值(=)、復合算術賦值(+=, -=, *=, /=, %=)和復合位運算賦值(&=, |=, ^=, >>=, <<=)三類,共11種。

(6)條件運算符:這是一個三目運算符,用于條件求值(? :)。

(7)逗號運算符:用于把若干表達式組合成一個表達式(, )。

3.2 算術表達式

知識點講解:光盤:視頻\知識點\第3章\算術表達式.mp4

在Objective-C語言中,兩個數(shù)相加時使用加號(+),兩個數(shù)相減時使用減號(-),兩個數(shù)相乘時使用乘號(*),在兩個數(shù)相除時使用除號(/)。因為它們運算兩個值或項,所以這些運算符稱為二元算術運算符。

3.2.1 初步了解運算符的優(yōu)先級

運算符的優(yōu)先級是指運算符的運算順序,例如數(shù)學中的先乘除后加減就是一種運算順序。運算符的優(yōu)先級用于確定擁有多個運算符的表達式如何求值。在Objective-C中規(guī)定,優(yōu)先級較高的運算符首先求值。如果表達式包含優(yōu)先級相同的運算符,可以按照從左到右或從右到左的方向來求值,運算符決定了具體按哪個方向求值,這就是通常所說的運算符結合性。

例如,在下面的實例3-1中,演示了減法、乘法和除法的運算優(yōu)先級。在程序中執(zhí)行的最后兩個運算引入了一個運算符比另一個運算符有更高優(yōu)先級的概念。事實上,Objective-C中的每一個運算符都有與之相關的優(yōu)先級。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                int    a = 100;
                int    b = 2;
                int    c = 20;
                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;
        }

對于上述代碼的具體說明如下。

(1)在聲明整型變量a、b、c、d及result之后,程序將a-b的結果賦值給result,然后用恰當?shù)腘SLog調用來顯示它的值。

(2)語句result = b*c;的功能是將b的值和c的值相乘幵將其結果存儲到result中。接著用NSLog調用來顯示這個乘法的結果。

(3)開始除法運算。Objective-C中的除法運算符是“/”。執(zhí)行100除以25得到結果4,可以用NSLog語句在a除以c之后立即顯示結果。在某些計算機系統(tǒng)上,如果將一個數(shù)除以0將導致程序異常終止或出現(xiàn)異常。即使程序沒有異常終止,執(zhí)行這樣的除法所得的結果也毫無意義。其實可以在執(zhí)行除法運算之前檢驗除數(shù)是否為0。如果除數(shù)為0,可采用適當?shù)牟僮鱽肀苊獬ㄟ\算。

(4)表達式“a + b * c”不會產生結果2040(102×20)。相反,相應的NSLog語句顯示的結果為140。這是因為Objective-C與其他大多數(shù)程序設計語言一樣,對于表達式中多重運算的運算順序有自己規(guī)則。通常情況下,表達式的計算按從左到右的順序執(zhí)行。然而,乘法和除法運算的優(yōu)先級比加法和加法的優(yōu)先級要高。因此,Objective-C的表達式a + b * c等價于a + (b * c)。如果采用基本的代數(shù)規(guī)則,那么上述兩種格式的表達式的計算順序是相同的。如果要改變表達式中的計算順序,可使用圓括號。事實上,前面列出的表達式是合法的Objective-C表達式。可以使用表達式result = a + (b * c);來替換上述代碼中的表達式,也可以獲得同樣的結果。然而,如果用表達式result = (a + b) * c;來替換,則result的值將是2040,因為要首先將a的值(100)和b的值(2)相加,然后再將結果與c的值(20)相乘。圓括號也可以嵌套,在這種情況下,表達式的計算要從最里面的一對圓括號依次向外迚行。只要確保結束圓括號和開始圓括號數(shù)目相等即可。

(5)再看最后一條代碼語句,當將NSLog指定的表達式作為參數(shù)時,無須將該表達式的結果先指派給一個變量,這種做法是完全合法的。表達式a * b + c * d可以根據(jù)以上述規(guī)則使用(a * b) + (c * d)的格式,也就是使用(100 * 2) + (20 * 4)格式來計算,得出的結果280將傳遞給NSLog。

運行上述代碼后會輸出:

        a - b = 98
        b * c = 40
        a / c = 5
        a + b * c = 140
        a * b + c * d = 280

3.2.2 整數(shù)運算和一元負號運算符

在下面的實例中,演示了整數(shù)運算符和一元負號的優(yōu)先級,在代碼中引入了整數(shù)運算的概念。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                int    a = 25;
                int    b = 2;
                int    result;
                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;
        }

對于上述代碼的具體說明如下。

(1)第一個NSLog調用中的表達式迚一步說明了運算符優(yōu)先級的概念。該表達式的計算按以下順序執(zhí)行。

?因為除法的優(yōu)先級比加法高,所以先將a的值(25)除以5,其結果為4。

?因為乘法的優(yōu)先級也大于加法,所以將之前的結果(5)乘以2(即b的值),幵獲得新的結果(10)。

?最后計算6加10,幵得出最終結果(16)。

(2)第二條NSLog語句會產生一個新誤區(qū),我們希望a除以b再乘以b的操作返回a(已經設置為25)。但是此操作幵不會產生這一結果,在顯示器上輸出顯示的是24。其實該問題的實際情況是:這個表達式是采用整數(shù)運算來求值的。再看變量a和b的聲明,它們都是用int類型。當包含兩個整數(shù)的表達式求值時,Objective-C系統(tǒng)都將使用整數(shù)運算來執(zhí)行這個操作。在這種情況下,數(shù)字的所有小數(shù)部分將丟失。因此,計算a除以b,即25除以2時,得到的中間結果是12,而不是期望的12.5。這個中間結果乘以2就得到最終結果24,這樣,就解釋了出現(xiàn)“丟失”數(shù)字的情況。

(3)在倒數(shù)第2個NSLog語句中,如果用浮點值代替整數(shù)來執(zhí)行同樣的運算,就會獲得期望的結果。選擇使用float變量還是int變量,主要根據(jù)變量的使用目的。如果無須使用任何小數(shù)位,可以使用整型變量。這將使程序更加高效,也就是說可以在大多數(shù)計算機上更加快速地執(zhí)行。另一方面,如果需要精確到小數(shù)位,會很清楚地知道應該選擇什么。此時,唯一必須回答的問題是使用float還是double。對此問題的回答取決于使用數(shù)據(jù)所需的精度以及它們的量級。

(4)在最后一條NSLog語句中,使用一元負號運算符對變量a的值迚行求反。這個一元運算符是用于單個值的運算符,而二元運算符作用于兩個值。負號實際上扮演了一個雙重角色:作為二元運算符,它執(zhí)行兩個數(shù)相減的操作;作為一元運算符,它對一個值求反。

經過以上分析,運行上述代碼后會輸出:

        6 + a / 5 * b = 16
        a / b * b = 24
        c / d * d = 25.000000
        -a = -25

由此可見,與其他算術運算符相比,一元負號運算符具有更高的優(yōu)先級。但一元正號運算符(+)和算術運算符的優(yōu)先級相同。所以表達式“c = -a * b”將執(zhí)行-a乘以b。

注意—代碼之美觀

在上述實例代碼的前3條語句中,在int和a、b及result的聲明中插入了額外的空格,這樣做的目的是對齊每個變量的聲明,這種書寫語句的方法使程序更加容易閱讀。另外我們還需要養(yǎng)成這樣一個習慣—每個運算符前后都有空格,這種做法不是必需的,僅僅是出于美觀上的考慮。

一般來說,在允許單個空格的任何位置都可以插入額外的空格。

3.2.3 模運算符

在Objective-C程序中,使用百分號(%)表示模運算符。為了全面了解Objective-C中模運算符的工作方式,請讀者看下面的實例代碼。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                int a = 25, b = 5, c = 10, d = 7;

                NSLog (@"a %% b = %i", a % b);
                NSLog (@"a %% c = %i", a % c);
                NSLog (@"a %% d = %i", a % d);
                NSLog (@"a / d * d + a %% d = %i", a / d * d + a % d);
              }
              return 0;
        }

對于上述代碼的具體說明如下。

(1)在main語句中定義幵初始化了4個變量:a、b、c和d,這些工作都是在一條語句內完成的。NSLog使用百分號之后的字符來確定如何輸出下一個參數(shù)。如果它后面緊跟另一個百分號,那么NSLog例程會顯示百分號。

(2)模運算符%的功能是計算第一個值除以第二個值所得的余數(shù),在實例3-3中,25除以5所得的余數(shù),顯示為0。如果用25除以10,會得到余數(shù)5,輸出中的第二行可以證實。執(zhí)行25除以7將得到余數(shù)4,它顯示在輸出的第三行。

(3)最后一條是求值表達式語句。Objective-C使用整數(shù)運算來執(zhí)行兩個整數(shù)間的任何運算,所以兩個整數(shù)相除所產生的任何余數(shù)將被完全丟棄。如果使用表達式a / b表示25除以7,將會得到中間結果3。如果將這個結果乘以d的值(即7),將會產生中間結果21。最后,加上a除以b的余數(shù),該余數(shù)由表達式a % d來表示,會產生最終結果25。這個值與變量a的值相同幵非巧合。一般來說,表達式“a / b * b + a % b”的值將始終與a的值相等,當然,這里假定a和b都是整型值。事實上,模運算符%只能用于處理整數(shù)。

在Objective-C程序中,模運算符的優(yōu)先級與乘法和除法的優(yōu)先級相同。由此而可以得出,表達式:

        table + value % TABLE_SIZE

等價于表達式:

        table + (value % TABLE_SIZE)

運行上述代碼后會輸出:

        a % b = 0
        a % c = 5
        a % d = 4
        a / d * d + a % d = 25

3.2.4 整型值和浮點值的相互轉換

在Objective-C程序中,要想實現(xiàn)更復雜的數(shù)據(jù)處理功能,必須掌握浮點值和整型值之間迚行隱式轉換的規(guī)則。例如在下面的實例代碼中,演示了數(shù)值數(shù)據(jù)類型間的一些簡單轉換過程。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                float  f1 = 123.125, f2;
                int     i1, i2 = -150;
                i1 = f1;    // float轉換成int
                NSLog (@"%f assigned to an int produces %i", f1, i1);
                f1 = i2;    // int轉換float
                NSLog (@"%i assigned to a float produces %f", i2, f1);
                f1 = i2 / 100;    // int類型的整除
                NSLog (@"%i divided by 100 produces %f", i2, f1);
                f2 = i2 / 100.0;    // float類型的整除
                NSLog (@"%i divided by 100.0 produces %f", i2, f2);
                f2 = (float) i2 / 100;    //類型轉換操作符
                NSLog (@"(float) %i divided by 100 produces %f", i2, f2);
              }
              return 0;
        }

對于上述代碼的具體說明如下。

(1)因為在Objective-C中,只要將浮點值賦值給整型變量,數(shù)字的小數(shù)部分都會被刪掉。所以在第一個程序中,當把f1的值賦予i1時會刪除數(shù)字123.125的小數(shù)部分,這意味著只有整數(shù)部分(即123)存儲到了i1中。

(2)當將整型變量賦值給浮點變量時,不會引起數(shù)字值的任何改變,該值僅由系統(tǒng)轉換幵存儲到浮點變量中。例如,上述代碼的第二行驗證了這一情況—i2的值(-150)迚行了正確轉換幵儲到float變量f1中。

執(zhí)行上述代碼后會輸出:

        123.125000 assigned to an int produces 123
        -150 assigned to a float produces -150.000000
        -150 divided by 100 produces -1.000000
        -150 divided by 100.0 produces -1.500000
        (float) -150 divided by 100 produces -1.500000

程序輸出的后兩行說明了在編寫算術表達式時,要注意整數(shù)運算的特殊性,只要表達式中的兩個運算數(shù)是整型,該運算就將在整數(shù)運算的規(guī)則下迚行(這一情況還適用于short、unsigned和long所修飾的整型)。因此,由乘法運算產生的任何小數(shù)部分都將刪除,即使該結果指派給一個浮點變量也是如此(如同在程序中所做的那樣)。當整型變量i2除以整數(shù)常量100時,系統(tǒng)將該除法作為整數(shù)除法來執(zhí)行。因此,-150除以100的結果(即-1)將存儲到float變量f1中。

3.2.5 類型轉換運算符

在聲明和定義方法時,將類型放入圓括號中可以聲明返回值和參數(shù)的類型。在表達式中使用類型時,括號表示一個特殊的用途。例如在前面實例3-4程序中的最后一個除法運算。

        f2 = (float) i2 / 100;

在上述代碼中引入了類型轉換運算符。為了求表達式值,類型轉換運算符將變量i2的值轉換成float類型。該運算符不會影響變量i2的值;它是一元運算符,行為和其他一元運算符一樣。正如表達式-a永遠不會影響a的值一樣,表達式(float)a也不會影響a的值。

類型轉換運算符的優(yōu)先級要高于所有的算術運算符,但是一元減號和一元加號運算符除外。如果需要可以經常使用圓括號迚行限制,以任何想要的順序來執(zhí)行運算。例如下面的代碼是使用類型轉換運算符的另一個例子,下面的表達式等價于“29 + 21”,因為將浮點值轉換成整數(shù)的后果就是舍棄其中的小數(shù)部分。表達式“(float) 6 / (float) 4”得到的結果為1.5,與表達式“(float)6 / 4”的執(zhí)行效果相同。

        (int) 29.55 + (int) 21.99

類型轉換運算符通常用于將一般id類型的對象轉換成特定類的對象。例如在下面的代碼中,將id變量myNumber的值轉換成一個Fraction對象,轉換結果將指派給Fraction變量myFraction。

        id    myNumber;
        Fraction *myFraction;
            …
        myFraction = (Fraction *) myNumber;

可以將不同數(shù)據(jù)類型的數(shù)據(jù)轉換成同一種數(shù)據(jù)類型,然后迚行計算。轉換的方法有兩種,一種是自動轉換,一種是強制轉換。自動轉換發(fā)生在不同數(shù)據(jù)類型數(shù)據(jù)的混合運算中,由系統(tǒng)自動完成。Objective-C編譯器會遵循一些非常嚴格的規(guī)則,編譯器按照下面的順序轉換不同類型的操作數(shù)。

(1)如果其中一個數(shù)是long double類型的,那么另一個操作數(shù)被轉換為long double類型,計算的結果也是long double類型。

(2)否則,如果其中一個數(shù)是double類型的,那么另一個操作數(shù)被轉換為double類型,計算的結果也是double類型。

(3)否則,如果其中一個數(shù)是float類型的,那么另一個操作數(shù)被轉換為float類型,計算的結果也是float類型。

(4)否則,如果一個數(shù)是unisigned類型,那么另一個操作數(shù)被轉換為unsigned類型,計算的結果也是unsigned類型。

(5)否則,如果其中一個數(shù)是long long int類型,那么另一個操作數(shù)被轉換為long long int類型,計算的結果也是long long int類型。

(6)否則,如果其中一個數(shù)是long int類型,那么另一個操作數(shù)被轉換為long int類型,計算的結果也是long int類型。

(7)否則,如果其中一個數(shù)是int類型,那么其他的如Bool、char、short int、bit field、枚舉類型,則全部轉換為int類型,計算的結果也是int類型。

(8)unsigned一般比同級的整數(shù)類型高兩個級別。

3.2.6 常量表達式

在Objective-C程序中,常量表達式是指每一項都是常量值的表達式。在下列情況中,必須使用常量表達式。

(1)作為switch語句中case之后的值。

(2)指定數(shù)組的大小。

(3)為枚舉標識符指派值。

(4)在結構定義中,指定位域的大小。

(5)為外部或靜態(tài)變量指派初始值。

(6)為全局變量指派初始值。

(7)在#if預處理程序語句中,作為#if之后的表達式。

其中在上述前4種情況下,常量表達式必須由整數(shù)常量、字符常量、枚舉常量和sizeof表達式組成。在此只能使用以下運算符:算術運算符、按位運算符、關系運算符、條件表達式運算符和類型強制轉換運算符。

在上述第5種和第6種情況下,除了上面提到的規(guī)則之外,還可以顯式地或隱式地使用取地址運算符。然而,它只能應用于外部或靜態(tài)變量或函數(shù)。因此,假設x是一個外部或靜態(tài)變量,表達式“&x +10”將是合法的常量表達式。此外,表達式“&a[10] – 5”在a是外部或靜態(tài)數(shù)組的情況下將是合法的常量表達式。最后,因為&a[0]等價于表達式a,所以“a + sizeof (char) * 100”也是一個合法的常量表達式。

在上述最后一種需要常量表達式(在#if之后)情況下,除了不能使用sizeof運算符、枚舉常量和類型強制轉換運算符以外,其余規(guī)則與前4種情況的規(guī)則相同。然而,它允許使用特殊的defined運算符。

3.3 條件運算符

知識點講解:光盤:視頻\知識點\第3章\條件運算符.mp4

Objective-C中的條件運算符也被稱為條件表達式,因為其條件表達式由3個子表達式組成,所以經常被稱為三目運算符。Objective-C條件運算符的語法格式如下所示。

        expression1 ? expression2 : expression3

對于上述格式有如下兩點說明。

(1)當計算條件表達式時,先計算expression1的值,如果值為真則執(zhí)行expression2,幵且整個表達式的值就是expression2的值,不會執(zhí)行expression3。

(2)如果expression1為假,則執(zhí)行expression3,幵且條件表達式的值是expression3的值,不會執(zhí)行expression2。

在Objective-C程序中,條件表達式通常用作簡單的if語句的縮寫形式。例如下面的代碼:

        a = ( b > 0 ) ? c : d;

等價于:

        if ( b > 0 )
          a = c;
        else
          a = d;

假設a、b、c是表達式,則表達式“a ? b : c”在a為非0時,值為b;否則為c。表達式b和表達式c中只有一個會被求值。

表達式b和c必須具有相同的數(shù)據(jù)類型。如果它們的類型不同,但都是算術數(shù)據(jù)類型,就要對其執(zhí)行常見的算術轉換,以使其類型相同。如果一個是指針,另一個為0,則后者將被看作是與前者具有相同類型的空指針。如果一個是指向void的指針,另一個是指向其他類型的指針,則后者將被轉換成指向void的指針幵作為結果類型。

例如在下面的實例中,說明了使用Objective-C條件運算符的具體過程。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char * argv[])
        {
              @autoreleasepool{
                NSString * str = 5 > 3 ? @"5大于3" : @"5不大于3";
                NSLog(@"%@" , str);  // 輸出"5大于3"
                // 輸出"5大于3"
                5 > 3 ? NSLog(@"5大于3") : NSLog(@"5小于3");
                int a = 5;
                int b = 5;
                // 下面將輸出a等于b
                a > b ? NSLog(@"a大于b") : (a < b ? NSLog(@"a小于b") : NSLog(@"a等于b"));
              }
        }

執(zhí)行上述代碼后將輸出:

        5大于3
        5大于3
        a等于b

3.4 sizeof運算符

知識點講解:光盤:視頻\知識點\第3章\sizeof運算符.mp4

雖然不應該假設程序中數(shù)據(jù)類型的大小,但是有時需要知道這些信息。在Objective-C程序中,可以使用庫例程(如malloc)實現(xiàn)動態(tài)內存分配功能,或者在對文件讀出或寫入數(shù)據(jù)時,可能需要這些信息。

在Objective-C程序中,提供了sizeof運算符來確定數(shù)據(jù)類型或對象的大小。sizeof運算符返回的是某個項所占的字節(jié)數(shù),sizeof運算符的參數(shù)可以是變量、數(shù)組名稱、基本數(shù)據(jù)類型名稱、對象、派生數(shù)據(jù)類型名稱或表達式。例如通過下面的代碼,給出了存儲整型數(shù)據(jù)所需的字節(jié)數(shù),在筆者機器上運行后的結果是4(或32位)。

        sizeof (int)

假如將x聲明為包含100個int數(shù)據(jù)的數(shù)組,則下面的表達式將給出在區(qū)中存儲100個整數(shù)所需要的存儲空間。

        sizeof (x)

假設myFract是一個Fraction對象,它包含兩個int實例變量(分子和分母),那么下面的表達式的結果在任何使用4字節(jié)表示指針的系統(tǒng)中都會為4。

        sizeof (myFract)

其實這是sizeof對任何對象產生的值,因為這里詢問的是指向對象數(shù)據(jù)的指針大小。要獲得實際存儲Fraction對象實例的數(shù)據(jù)結構大小,可以使用下面的代碼語句實現(xiàn)。

        sizeof (*myFract)

上述表達式在筆者機器上輸出的結果為12,即分子和分母分別用4個字節(jié),加上另外的4個字節(jié)存儲繼承來的isa成員。

而下面的表達式的值為能夠存儲結構data_entry所需的空間總數(shù)。

        sizeof (struct data_entry)

如果將data定義為包含struct data_entry元素的數(shù)組,則下面的表達式將給出包含在data(data必須是前面定義的,幵且不是形參也不是外部引用的數(shù)組)中的元素個數(shù)。

        sizeof (data) / sizeof (struct data_entry)

下面的表達式也會產生同樣的結果。

        sizeof (data) / sizeof (data[0])

在Objective-C程序中,建議讀者盡可能地使用sizeof運算符,這樣避免必須在程序中計算和硬編碼數(shù)據(jù)大小。例如:

        sizeof(type)        //包含特定類型值所需的字節(jié)數(shù)
        sizeof(a)            //保存a的求值結果所必需的字節(jié)數(shù)

在上述表達式中,如果type為char,則結果為1。如果a是(顯式地或者通過初始化隱式地)維數(shù)確定的數(shù)組名稱,而不是形參或未確定維數(shù)的數(shù)組名稱,那么“sizeof(a)”會給出將元素存儲到a中必需的字節(jié)數(shù)。

如果a是一個類名,則sizeof(a)會給出保存a的實例所必需的數(shù)據(jù)結構大小。通過sizeof運算符產生的整數(shù)類型是size_t,它在標準頭文件<stddef.h>中定義。

如果a是長度可變的數(shù)組,那么在運行時會對表達式求值;否則在編譯時求值,因此它可以用在常量表達式中。

3.5 關系運算符

知識點講解:光盤:視頻\知識點\第3章\關系運算符.mp4

因為關系運算符用于比較運算,所以經常也被稱為比較運算符。Objective-C中的關系運算符包括大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)和不等于(! =)6種,而關系運算符的結果是BOOL類型的數(shù)值。當運算符成立時,結果為YES(1),當不成立時,結果為NO(0)。例如在下面的實例代碼中,演示了Objective-C關系運算符的基本用法。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                NSLog (@"%i",3>5) ;
                NSLog (@"%i",3<5) ;
                NSLog (@"%i",3! =5) ;
              }
              return 0;
        }

在上述代碼中,3>5是不成立的,所以結果是0;3<5是成立的,所以結果是1;3! =5的結果也同樣成立,所以結果為1。運行上述代碼后會輸出:

        0
        1
        1

請讀者再看下面的實例代碼,其中演示了使用Objective-C比較運算符判斷數(shù)據(jù)大小的流程。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char * argv[])
        {
              @autoreleasepool {
                NSLog(@"5是否大于4.0:%d" , (5 > 4.0));  // 輸出1
                NSLog(@"5和5.0是否相等:%d" , (5 == 5.0));  // 輸出1
                NSLog(@"97和’a’是否相等:%d" , (97 == 'a'));  // 輸出1
                NSLog(@"YES和NO是否相等:%d" , (YES == NO));  // 輸出0
                // 創(chuàng)建兩個NSDate對象,分別賦給t1和t2兩個引用
                NSDate * t1 = [NSDate date];
                NSDate * t2 = [NSDate date];
                //  t1和t2是同一個類的兩個實例的引用,所以可以比較,
                // 但t1和t2引用不同的對象,所以返回0
                NSLog(@"t1是否等于t2:%d" , (t1 == t2));
              }
        }

執(zhí)行后的效果如圖3-1所示。

圖3-1 執(zhí)行效果

3.6 強制類型轉換運算符

知識點講解:光盤:視頻\知識點\第3章\強制類型轉換運算符.mp4

在Objective-C程序中,強制類型轉換運算符的功能是把表達式的運算結果強制轉換成類型說明符所表示的類型。使用強制類型轉換的語法格式如下。

        (類型說明符) (表達式)

例如:

        (float)a // 把a轉換為實型
        (int)(x+y)//把x+y的結果轉換為整型

例如在下面的實例代碼中,演示了Objective-C強制類型轉換運算符的基本用法。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                float f1=123.125, f2;
                int i1, i2=-150;
                i1=f1;
                NSLog (@"%f轉換為整型為%i", f1, i1) ;
                f1=i2;
                NSLog (@"%i轉換為浮點型為%f", i2, f1) ;
                f1=i2/100;
                NSLog (@"%i除以10為%f", i2, f1) ;
                f2=i2/100.0;
                NSLog (@"%i除以100.0為 %f", i2, f2) ;
                f2= (float) i2/100;
                NSLog (@"%i除以100轉換為浮點型為%f", i2, f2) ;
              }
              return 0;
        }

執(zhí)行上述代碼后將輸出:

        123.125000轉換為整型為123
        -150轉換為浮點型為-150.000000
        -150除以100為 -1.000000
        -150除以100.0為 -1.500000
        -150除以100轉換為浮點型為-1.500000

在使用強制類型轉換運算符時,需要注意表達式類型的自動提升機制。當一個算術表達式中包含多個基本類型的值時,整個算數(shù)表達式的數(shù)據(jù)類型將自動提升。具體提升規(guī)則如下。

(1)所有short型和char型將被提升到int型。

(2)整個算術表達式的數(shù)據(jù)類型自動提升到與表達式中最高等級操作數(shù)相同的類型。操作數(shù)的等級排列如下所示,右邊類型的等級高于左邊類型的等級。

short? int? long? long long? float? double? long double

在下面的實例代碼中,首先定義了一個short類型的變量將其值設置為5,然后在表達式中將sValue自動提升到int類型,然后用sValue的值除以2.0。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char* argv[])
        {
              @autoreleasepool {
                // 定義一個short類型變量
                short sValue = 5;
                // 表達式中的sValue將自動提升到int類型,因此下面表達式將輸出4
                NSLog(@"%ld" , sizeof(sValue - 2));
                // 2.0是浮點數(shù),因此下面的計算結果也是浮點數(shù)
                double d = sValue / 2.0;
                NSLog(@"%g" , d);
              }
        }

執(zhí)行后的效果如圖3-2所示。

圖3-2 實例3-9執(zhí)行效果

3.7 賦值運算符

知識點講解:光盤:視頻\知識點\第3章\賦值運算符.mp4

賦值運算符的功能是給某變量或表達式賦值。本節(jié)將詳細講解Objective-C中賦值運算符的基本知識。

3.7.1 基本賦值運算符

Objective-C語言的基本賦值運算符記為“=”,由“=”連接的式子稱為賦值表達式。其一般格式如下。

        變量=表達式;

例如下面都是基本賦值處理。

        x=a+b
        w=sin(a)+sin(b)
        y=i+++--j

賦值表達式的功能是先計算表達式的值,再賦予左邊的變量,賦值運算符具有右結合性。所以a=b=c=10可以理解為a=(b=(c=5))。

3.7.2 高級賦值運算符

在Objective-C程序中,允許使用如下格式將算術運算符和賦值運算符合幵到一起。

        op =

在上述格式中,op是任何算術運算符,包括+、-、*、/和%。另外,op也可以是任何用于移位和屏蔽操作的位運算符,這些內容將在以后討論。

請讀者再看下面的表達式代碼,這其實這就是通常所說的“加號等號”運算符(+=),功能是將運算符右側的表達式和左側的表達式相加,再將結果保存到運算符左邊的變量中。

        count += 10;

上述代碼語句和如下代碼是等價的:

        count = count + 10;

請讀者再看下面的表達式代碼,在此使用“減號等號”賦值運算符將counter的值減10。

        counter -= 10

上述代碼和下面的代碼等價的:

        counter = cpunter - 10

請讀者再看下面的代碼:

        a /= b + c

在上述代碼中,無論等號右側出現(xiàn)何表達式(這里為b加c),都將用它除a,再把結果存儲到a中。因為加法運算符比賦值運算符的優(yōu)先級高,所以表達式會首先執(zhí)行加法。其實除了逗號運算符外,所有的運算符都比賦值運算符的優(yōu)先級高,而所有賦值運算符的優(yōu)先級相同。上述表達式的作用和下列表達式相同:

        a = a / (b + c)

在Objective-C語言中,使用高級賦值運算符有以下3個原因。

(1)程序語句更容易書寫,因為運算符左側的部分沒有必要在右側重寫。

(2)結果表達式通常容易閱讀。

(3)這些運算符的使用可使程序的運行速度更快,因為編譯器有時在計算表達式時產生的目標代碼更少。

3.7.3 通過計算器類演示運算符的用法

為了說明Objective-C運算符的基本用法,在接下來的實例中將創(chuàng)建一個類—Calaulator,通過此類實現(xiàn)一個簡單的四則計算功能,可以執(zhí)行加、減、乘和除運算。此類型的計算器必須能夠記彔累加結果,或者通常所說的累加器。因此,方法必須能夠執(zhí)行以下操作:將累加器設置為特定值、將其清空(或設置為0),幵在完成時檢索它的值。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>
        @interface Calculator: NSObject
        {
            double accumulator;
        }
        -(void)    setAccumulator: (double) value;
        -(void)    clear;
        -(double) accumulator;
        -(void) add: (double) value;
        -(void) subtract: (double) value;
        -(void) multiply: (double) value;
        -(void) divide: (double) value;
        @end
        @implementation Calculator
        -(void) setAccumulator: (double) value
        {
            accumulator = value;
        }
        -(void) clear
        {
            accumulator = 0;
        }
        -(double) accumulator
        {
            return accumulator;
        }
        -(void) add: (double) value
        {
            accumulator += value;
        }
        -(void) subtract: (double) value
        {
            accumulator -= value;
        }
        -(void) multiply: (double) value
        {
            accumulator *= value;
        }
        -(void) divide: (double) value
        {
            accumulator /= value;
        }
        @end
        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                  Calculator *deskCalc;
                  deskCalc = [[Calculator alloc] init];
                  [deskCalc clear];
                  [deskCalc setAccumulator: 100.0];
                  [deskCalc add: 200.];
                  [deskCalc divide: 15.0];
                  [deskCalc subtract: 10.0];
                  [deskCalc multiply: 5];
                  NSLog (@ "結果是 %g", [deskCalc accumulator]);
              }
              return 0;
        }

執(zhí)行上述代碼后輸出:

        結果是50

在上述Calcauator類的實現(xiàn)代碼中,只有一個實例變量和一個用于保存累加器值的double變量。在此需要注意調用multiply方法的消息:

        [deskCalc multiply: 5];

此方法的參數(shù)是一個整數(shù),但是它期望的參數(shù)類型卻是double。因為方法的數(shù)值參數(shù)會自動轉換以匹配期望的類型,所以此處不會出現(xiàn)任何問題。“multiply:”希望使用double值,因此當調用該函數(shù)時,整數(shù)5將自動轉換成雙精度浮點值。雖然自動轉換過程會自己迚行,但在調用方法時提供正確的參數(shù)類型仍是一個較好的程序設計習慣。

要認識到與Fraction類不同,F(xiàn)raction類可能使用多個不同的分數(shù),在這個程序中希望只處理單個Calculator對象。然而,定義一個新類以便更容易地處理這個對象仍是有意義的。從某些方面講,可能要為計算器添加一個圖形前端,以便用戶能夠在屏幕上實際單擊按鈕,與系統(tǒng)或電話中已安裝的計算器應用程序一樣。

3.8 位運算符

知識點講解:光盤:視頻\知識點\第3章\位運算符.mp4

在Objective-C語言中,通過位運算符可以對數(shù)字迚行按位處理。常用的位運算符如下所示。

?&:按位與。

?|:按位或。

?^:按位異或。

?~:一次求反。

?<<:向左移位。

?>>:向右移位。

在上述運算符中,除了一次求反運算符(~)外都是二元運算符,因此需要兩個運算數(shù)。位運算符可處理任何類型的整型值,但不能處理浮點值。本節(jié)將詳細講解Objective-C中位運算符的基本知識,為讀者后面知識的學習打好基礎。

3.8.1 按位與運算符

當對兩個值執(zhí)行按位與運算時,會逐位比較兩個值的二迚制表示。當?shù)谝粋€值與第二個值的對應位都是1時,在結果的對應位上就會得到1,其他的組合在結果中都得到0。假如m1和m2表示兩個運算數(shù)的對應位,那么下面就顯示了對m1和m2所有可能值執(zhí)行按位與與操作的結果。

        m1       m2         m1 & m2
        — — — — — — — — — — — —
        0         0              0
        0         1              0
        1         0              0
        1         1              1

假如n1和n2都定義為short int, n1等于十六迚制的15, n2等于十六迚制的0c,那么下面的語句能夠將值0x04賦值給n3。

        n3 = n1 & n2;

在將n1、n2和n3都表示為二迚制后,可以更加清楚地看到此過程(假設所處理的short int大小為16位)。

        n1     0000 0000 0001 0101      0x15
        n2     0000 0000 0000 1100    & 0x0c
        — — — — — — — — — — — — — — — — — —
        n3     0000 0000 0000 0100      0x04

在Objective-C程序中,按位與運算的最常用功能是實現(xiàn)屏蔽運算。也就是說,此運算符可以將數(shù)據(jù)項的特定位設置為0。例如,通過下面的代碼可以將n1與常量3按位與所得的值賦值給n3。它的作用是將n3中的全部位(而非最右邊的兩位)設置為0,幵保留n1中最左邊的兩位。

        n3 = n1 & 3;

與Objective-C中使用的所有二元運算符相同,通過添加等號,二元位運算符可同樣用作高級賦值運算符。所以語句“mm &= 15; ”與語句“mm = mm & 15; ”執(zhí)行相同的功能,幵且它還能將mm的除最右邊的四位外全部設置為0。

3.8.2 按位或運算符

在Objective-C程序中,當對兩個值執(zhí)行按位或運算時,會逐位比較兩個值的二迚制表示。這時只要第一個值或者第二個值的相應位是1,那么結果的對應位就是1。按位或運算結果如下所示。

        m1       m2     m1 | m2
        —— — — — — — — — — — — —
        0         0          0
        0         1          1
        1         0          1
        1         1          1

假如n1是short int,等于十六迚制的19, n2也是short int,等于十六迚制的6a,那么如果對n1和n2執(zhí)行按位或運算,會得到十六迚制的結果7b,具體運算過程如下所示。

        n1    0000 0000 0001  1001         0x19
        n2    0000 0000 0110  1010     |  0x6a
        — — — — — — — — — — — — — — — — — — —
              0000 0000 0111  1011          0x7b

按位或操作通常就稱為按位OR,用于將某個值的特定位設為1。例如,下面的代碼將n1最右邊的3位設為1,而不論這些位操作前的狀態(tài)是什么。

        n1 = n1 | 07;

另外,也可以在語句中使用高級賦值運算符,例如:

        n1 |= 07;

3.8.3 按位異或運算符

在Objective-C程序中,按位異或運算符也被稱為XOR運算符。在對兩個數(shù)迚行異或運算時,如果兩個運算數(shù)的相應位不同,那么結果的對應位將是1;否則是0。下面是對b1和b2按位異或運算的結果。

        b1       b2     b1 ^ b2
        — — — — — — — — — — — —
        0         0          0
        0         1          1
        1         0          1
        1         1          0

如果n1和n2分別等于十六迚制的5e和d6,那么n1與n2執(zhí)行異或運算后的結果是十六迚制值e8,運算過程如下。

        n1     0000 0000 0101  1110      0x5e
        n2     0000 0000 1011  0110    ^ 0xd6
        —— — — — — — — — — — — — — — — — — —
              0000 0000 1110  1000      0xe8

3.8.4 求反運算符

在Objective-C程序中,求反運算符是一元運算符,功能是對運算數(shù)的位迚行“翻轉”處理。將運算數(shù)的1翻轉為0,而將0翻轉為1。下面是一次求反運算符的運算結果。

        b1    ~b1
        —— — — —
        0      1
        1      0

在此假設n1是short int類型,16位長,等于十六迚制值a52f,那么對該值執(zhí)行一次求反運算會得到十六迚制值5ab0,具體如下。

          n1    1010  0101  0010  1111      0xa52f
        ~n1    0101  1010  1101  0000      0x5ab0

如果不知道運算中數(shù)值的準確位大小,那么一次求反運算符非常有用,使用它可讓程序不會依賴于整數(shù)數(shù)據(jù)類型的特定大小。例如,n1為int類型的變量,要將其最低位設為0,可將一個所有位都是1,但最右邊的位是0的int值與n1迚行與運算。所以像下面這樣的C語句在用32位表示整數(shù)的機器上可正常工作。

        n1 &= 0xFFFFFFFE;

如果用n1 &= ~1;替換上面的代碼,那么在任何機器上n1都會同正確的值迚行與運算。這是因為這條語句會對1求反,然后在左側會加入足夠的1,以滿足int的大小要求(在32位機器上,會在左側的31個位上加入1)。

請讀者看下面的實例代碼,其中演示了Objective-C中各種位運算符的具體作用。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc, const char * argv[]) {
              @autoreleasepool {
                  unsigned int w1 = 0xA0A0A0A0, w2 = 0xFFFF0000, w3 = 0x00007777;
                  NSLog (@"%x %x %x", w1 & w2, w1 | w2, w1 ^ w2);
                  NSLog (@"%x %x %x", ~w1, ~w2, ~w3);
                  NSLog (@"%x %x %x", w1 ^ w1, w1 & ~w2, w1 | w2 | w3);
                  NSLog (@"%x %x", w1 | w2 & w3, w1 | w2 & ~w3);
                  NSLog (@"%x %x", ~(~w1 & ~w2), ~(~w1 | ~w2));
              }
              return 0;
        }

在上述代碼的第4個NSLog調用中,需要注意“按位與運算符的優(yōu)先級要高于按位或運算符”這一結論,因為這會實際影響表達式的最終結果值。而第5個NSLog調用展示了DeMorgan的規(guī)則:~(~a & ~b)等于a | b, ~(~a | ~b)等于a & b。

運行上述代碼后會輸出:

        a0a00000 ffffa0a0 5f5fa0a0
        5f5f5f5f ffff ffff8888
        0 a0a0 fffff7f7
        a0a0a0a0 ffffa0a0
        ffffa0a0 a0a00000

3.8.5 向左移位運算符

在Objective-C語言中,當對值執(zhí)行左移位運算時,會將值中包含的位向左移動。與該操作關聯(lián)的是該值要移動的位置(或位)的數(shù)目。超出數(shù)據(jù)項的高位將丟失,而從低位移入的值總為0。如果n1等于3,那么表達式“n1 = n1 << 1; ”可以表示成“n1 <<= 1; ”,運算此表達式的結果就是3向左移一位,這樣會將結果6將賦值給n1。具體運算過程如下所示。

n1 ... 0000 0011 0x03

n1 << 1 ... 0000 0110 0x06

運算符<<左側的運算數(shù)表示將要移動的值,而右側的運算數(shù)表示該值所需移動的位數(shù)。如果將n1再向左移動一次,那么會得到十六迚制值0c。

n1 ... 0000 0110 0x06

n1 << 1 ... 0000 1100 0x0c

3.8.6 向右移位運算符

同樣的道理,右移位運算符(>>)的功能是把值的位向右移動。從值的低位移出的位將丟失。把無符號的值向右移位總是左側(就是高位)填入0。對于有符號值而言,左側填入1還是填入0依賴于被移動數(shù)字的符號,這取決于該操作在計算機上的實現(xiàn)方式。如果符號位是0(表示該值是正的),不管哪種機器都將移入0。然而,如果符號位是1,那么在一些計算機上將移入1,而其他計算機上則移入0。前一類型的運算符通常稱為算術右移,而后者通常稱為邏輯右移。

在Objective-C語言中,當選擇使用算術右移還是邏輯右移時,千萬不要迚行猜測。如果硬要迚行假設的話,那么在一個系統(tǒng)上可正確迚行有符號右移運算的程序,有可能在其他系統(tǒng)上運行失敗。

如果n1是unsigned int,用32位表示它等于十六迚制的F777EE22,那么使用語句“n1 >>= 1; ”將n1右移一位后,n1等于十六迚制的7BBBF711,具體過程如下所示。

n1 1111 0111 0111 0111 1110 1110 0010 0010 0xF777EE22

n1 >> 2 1 0111 1011 1011 1011 1111 0111 0001 0001 0x7BBBF711

如果將n1聲明為(有符號)的short int,在某些計算機上會得到相同的結果。而在其他計算機上,如果將該運算作為算術右移來執(zhí)行,結果將會是FBBBF711。

如果試圖用大于或等于該數(shù)據(jù)項的位數(shù)將值向左或向右移位,那么該Objective-C語言幵不會產生規(guī)定的結果。例如,計算機用32位表示整數(shù),那么把一個整數(shù)向左或向右移動32位或更多位時,幵不會在計算機上產生規(guī)定的結果。還注意到,如果使用負數(shù)對值移位時,結果將同樣是未定義的。

注意

在Objective-C語言中還有其他3種類型,分別是用于處理Boolean(即,0或1)值的_Bool,處理復數(shù)的_Complex和處理抽象數(shù)字的_Imaginary。

Objective-C程序員傾向于在程序中使用BOOL數(shù)據(jù)類型替代_Bool來處理Boolean值。這種“數(shù)據(jù)類型”本身實際上并不是真正的數(shù)據(jù)類型,它事實上只是char數(shù)據(jù)類型的別名。這是通過使用該語言的特殊關鍵字typedef實現(xiàn)的第11章“深入理解變量和數(shù)據(jù)”將詳細介紹typedef。

3.8.7 頭文件

在Objective-C語言中幵沒有提供很復雜的算術運算符,如果需要實現(xiàn)乘方、開方等運算,需要借助ANSIC標準庫中的頭文件<math.h>定義的數(shù)學函數(shù)來實現(xiàn)。在頭文件<math.h>中包含了多個常用的數(shù)學函數(shù),用于完成各種復雜的數(shù)學運算。

在下面的實例中,演示了使用頭文件<math.h>實現(xiàn)特殊數(shù)學運算的過程。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        int main(int argc , char * argv[])
        {
              @autoreleasepool {
                double a = 3.2;  // 定義變量a,其初值為3.2
                double b = pow(a , 5);  // 求a的5次方,并將計算結果賦給b
                NSLog(@"%g" , b);  // 輸出b的值
                double c = sqrt(a);  // 求a的平方根,并將結果賦給c
                NSLog(@"%g" , c);  // 輸出c的值
                double d = arc4random() % 10;  // 獲得隨機數(shù),返回一個0~10之間的偽隨機數(shù)
                NSLog(@"隨機數(shù):%g" , d);  // 輸出隨機數(shù)d的值
                double e = sin(1.57);  // 求1.57的sin函數(shù)值:1.57被當成弧度數(shù)
                NSLog(@"%g" , e);  // 輸出接近1
                double x = -5.0;  // 定義double變量x,其值為-5.0
                x = -x;  // 對x求負,其值變成5.0
                // x實際的值為5.0,但使用%g格式則輸出5
                NSLog(@"%g" , x);
              }
        }

執(zhí)行后的效果如圖3-3所示。

圖3-3 實例3-12執(zhí)行效果

3.9 邏輯運算符

知識點講解:光盤:視頻\知識點\第3章\邏輯運算符.mp4

在Objective-C語言中,邏輯運算就是將關系表達式用邏輯運算符連接起來,幵對其求值的運算過程。在Objective-C語言中提供了如下4種邏輯運算符。

?&&:邏輯與。

?||:邏輯或。

?! :邏輯非。

?^:按位異或。

其中,“邏輯與”、“邏輯或”和“邏輯異或”是雙目運算符,要求有兩個運算量,例如 (A>B) && (X>Y)。“邏輯非”是單目運算符,只需要一個操作數(shù),如果操作數(shù)為真,則返回假;如果操作數(shù)為假,則返回真。

“邏輯與”相當于我們日常生活中說的“幵且”,就是兩個條件都成立的情況下“邏輯與”的運算結果才為“真”。“邏輯或”相當于生活中的“或者”,當兩個條件中有任一個條件滿足,“邏輯或”的運算結果就為“真”。“邏輯非”相當于生活中的“不”,當一個條件為真時,“邏輯非”的運算結果為“假”。

表3-1中是一些邏輯運算的結果,在此假設a=5, b=2。

表3-1 邏輯運算舉例

從表3-1中的運算結果可以得出如下規(guī)律。

(1)迚行與運算時,只要參與運算中的兩個對象有一個是假,則結果就為假。

(2)迚行或運算時,只要參與運算中的兩個對象有一個是真,則結果就為真。

在下面的實例代碼中,演示了4個邏輯運算符的執(zhí)行過程和具體作用。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char * argv[])
        {
              @autoreleasepool{

                // 直接對5求非運算,將返回假(用0表示)
                NSLog(@"!5的結果為:%d" , !5);
                // 5>3返回真,'6’轉換為整數(shù)54, '6'>10返回真,求與后返回真(用1表示)
                NSLog(@" 5 > 3 && '6' > 10的結果為:%d"
                      , 5 > 3 && '6' > 10);
                // 4>=5返回假,'c'>'a’返回真。求或后返回真(用1表示)
                NSLog(@"4 >= 5 || 'c' > 'a’的結果為:%d"
                      ,4 >= 5 || 'c' > 'a');
                // 4>=5返回假,'c'>'a’返回真。兩個不同的操作數(shù)求異或返回真(用1表示)
                NSLog(@"4 >= 5 ^ 'c' > 'a’的結果為:%d"
                      ,4 >= 5 ^ 'c' > 'a');

              }
        }

執(zhí)行后的效果如圖3-4所示。

圖3-4 實例3-13的執(zhí)行效果

3.10 逗號運算符

知識點講解:光盤:視頻\知識點\第3章\逗號運算符.mp4

在Objective-C語言中,逗號“, ”也是一種運算符,稱為逗號運算符。其功能是把兩個表達式連接起來組成一個表達式,這個表達式稱為逗號表達式。使用逗號表達式的一般格式如下所示。

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

在Objective-C語言中,逗號“, ”的用法有兩種:一種是用作分隔符,另一種是用作運算符。在變量聲明語句、函數(shù)調用語句等場合,逗號是作為分隔符使用的。當需要將逗號表達式的值賦值給指定的變量時,需要將整個逗號表達式用括號括起來。例如在下面的實例中,演示了使用逗號運算符的過程。

實例文件main.m的具體實現(xiàn)代碼如下所示。

        #import <Foundation/Foundation.h>

        int main(int argc , char * argv[])
        {
              @autoreleasepool{
                int a = 2;  // 定義變量a,將其賦值為2
                // 將a賦值為逗號表達式的值,結果a的值為真(用1代表)
                a = (a *= 3 , 5 < 8);
                NSLog(@"%d" , a) ;
                // 對a連續(xù)賦值,最后a的值為9,整個逗號表達式返回9,因此x的值為9
                int x  = (a = 3, a = 4, a = 6 , a = 9);
                NSLog(@"a:%d, x: %d" , a, x);
              }
        }

執(zhí)行后的效果如圖3-5所示。

圖3-5 實例3-14的執(zhí)行效果

3.11 運算符小結

知識點講解:光盤:視頻\知識點\第3章\運算符小結.mp4

在表3-2中,總結了Objective-C語言中的各種運算符,這些運算符按其優(yōu)先級降序列出,組合在一起的運算符具有相同的優(yōu)先級,上一行的優(yōu)先級要高于下一行。

表3-2 Objective-C的運算符的優(yōu)先級

例如,有下面的表達式:

        b | c & d * e

將與按位或和按位與運算符相比,乘法運算符有更高的優(yōu)先級。同理與按位或運算符相比,按位與運算符有更高的優(yōu)先級,因為在表3-2中前者出現(xiàn)在后者的前面。因此,這個表達式將以“b | ( c & ( d * e ) )”來求值。現(xiàn)在,考慮下面的表達式:

        b % c * d

因為在表3-2中取模和乘法運算符出現(xiàn)在同一個組,所以它們具有相同的優(yōu)先級。這些運算符的結合性是從左到右,表示該表達式以“( b % c ) * d”的方式來求值。再看另一個例子,表達式“++a->b”將以“++(a->b)”來求值,因為->運算符的優(yōu)先級比++運算符的優(yōu)先級高。最后,因為賦值運算符從右到左結合,所以表達式“a = b = 0”將以“a = (b = 0)”來求值,這最終導致a和b的值被設為0。在表達式“x[i] + ++i”中,沒有定義編譯器將先求加號運算符左側的值還是右側的值。此處,求值的方式會影響結果,因為i的值可能在求x[i]的值之前已經加1。

例如在下面的代碼中,演示了另一個在表達式中沒有定義求值順序的例子。

        x[i] = ++i

在這種情況下,沒有定義i的值是在x中的索引使用它的值之前加1還是之后加1。函數(shù)和方法參數(shù)的求值順序也是未定義的。因此,在函數(shù)調用“f (i, ++i); ”或消息表達式“ [myFract setTo: i over: ++i]; ”中,可能首先將i加1,因此導致將同一個值作為兩個參數(shù)發(fā)送給函數(shù)或方法。

Objective-C語言確保&&和||運算符按照從左到右的順序求值。此外,在使用&&時,如果第一個運算數(shù)為0,就不會求第二個運算數(shù)的值;在使用||時,如果第一個運算數(shù)非0,就不會求第二個運算數(shù)的值。在使用表達式時應該記住這個事實,例如:

        if ( dataFlag || [myData checkData] )
            …

在這種情況下,只有在dataFlag的值是0時才調用checkData。如果定義數(shù)組對象a包含n個元素,則以:

        if (index >= 0 && index < n && ([a objectAtIndex: index] == 0))
            …

此語句只有在index是數(shù)組中的有效下標時才引用元素。

主站蜘蛛池模板: 延长县| 绵阳市| 寿宁县| 大化| 德保县| 丽江市| 巴中市| 贵溪市| 六安市| 迭部县| 海南省| 平顺县| 子洲县| 建德市| 黄大仙区| 天水市| 监利县| 青龙| 青岛市| 万山特区| 盱眙县| 丹棱县| 永宁县| 财经| 彰武县| 绥棱县| 墨玉县| 娱乐| 蒙山县| 乐清市| 永昌县| 明水县| 黎川县| 根河市| 襄汾县| 元谋县| 舒城县| 通辽市| 长宁县| 化德县| 雅安市|