運算子優先順序及結合順序隨筆
最近在網上看到一段開原始碼中有一個關於鏈表操作的代碼,其中有一行如下:
--pNode->next;
看到這段代碼,我一時想不起這些運算子的結合順序是什麼樣子了,於是開始尋找資料並寫了下面的測試程式:
1 // test operator priority 2 typedef struct 3 { 4 int* next; 5 } SturctA; 6 7 int a[] = {0, 1, 2, 3 }; 8 int b = 4; 9 SturctA temp1[2];10 SturctA *pTemp1 = &temp1[0];11 int val1 = 0, val2 = 0, val3 = 0;12 13 temp1[0].next = &a[2];14 temp1[1].next = &b;15 16 val1 = *--pTemp1->next; // equals to *(--(pTemp1->next)); after operation val1 = 1, pTemp1 = &temp1[0]17 NSLog(@"val1 value: %d", val1);18 19 val2 = *--pTemp1++->next; // equals to *(--(pTemp1->next)), then pTemp1++; after operation val2 = 0, pTemp1 = &temp1[1]20 NSLog(@"val2 value: %d", val2);21 22 val3 = *pTemp1->next;23 NSLog(@"val3 value: %d", val3);
這段代碼主要作用是驗證前++、--,後++、--,以及->,*的優先順序和結合順序。
程式中第2到5行,首先定義了一個結構體,該結構體中有一個指向int型的指標。第9行定義了一個結構體數組temp1[2],緊接著在第10行定義一個指向結構體數組第0個元素的指標pTemp1。13,14兩行分別對數組temp1的兩個結構體的next成員變數賦初值。最後16到23行對以上提到的四種的運算子進行了幾種組合,並列印測試結果。
下面我們分別看一下幾種運算子組合的具體情況:
- 第16行代碼,改行包含了前--,->以及*運算子。結合順序是首先pTemp1->next,然後在對拿到的next進行前--的操作,最後再取出--運算以後的指標所指向的數值。根據分析我們可以得到val1 = 1的結果。
- 第19行代碼,在前面執行的基礎上(前面的執行已經修改了next指標的指向)進行了前--,後++,->以及*操作。結合順序是首先pTemp1進行後++的操作(注:後++操作的運算子優先順序最高,但不會影響本次執行),然後在和->next結合獲得next的值(指向int的指標),接著再對該指標進行前--操作,最後對再取出--運算以後的指標所指向的數值。根據分析我們可以得到val2 = 0的結果(需要考慮到執行完第16行,pTemp1->next已經指向a[1]的地址)。
- 第22行代碼,在前面執行的基礎上,對pTemp1的後++操作進行了驗證,可以明顯的看出此時pTemp1已經指向結構體數組的第1個元素了。
上述代碼只是為了驗證運算子的優先順序問題,日常的代碼中還是盡量避免這樣寫,特別是不要想19行那樣,建議最好加上“()”,例如19行的代碼就可以修改為下面這樣:
val2 = *(--((pTemp1++)->next));
總之如果不清楚優先順序和結合順序,就多加一些“()”,這樣自己看起來清晰,也方面後面維護代碼的同事。