宏定義裡面為什麼要加括弧?
在宏定義當中,常常可以看到宏的參數以及整個宏的定義都被小括弧包圍,就像下面的 MIN、MAX、ABS 宏一樣:
上面的圖截取自 iOS 的系統庫,那為什麼它們需要這些括弧包圍起來呢?
下面假如我們自定義了宏 ceil_div,程式碼如下:
#define ceil_div(x, y) (x + y - 1) / y
這個宏的本意是將 x 除以 y,然後將得到的結果向上取整。比如 x = 4,y = 3,那麼 ceil_div(4, 3) 的值就是2。如果參數僅僅是這些數字,使用起來沒有什麼問題,cei_div(4, 3) 經過宏擴展之後成為:
(4 + 3 - 1) / 3
這個符合預期。但是假如參數變得複雜,包含了一些運算符,比如 ceil_div(b & c, sizeof(int)),講過宏擴展成為下面的樣子:
(b & c + sizeof(int) -1 ) / sizeof(int)
由於 & 的優先順序比算數運算符 + 的優先順序低,那麼實際上的運算過程是下面這樣的:
(b & (c + sizeof(int)) -1 ) / sizeof(int)
而期望的運算結果是先進行 & 運算,後進行 + 運算:
((b & c) + sizeof(int) -1 ) / sizeof(int)
所以,如果對於宏參數 x、y 不加括弧,顯然在涉及操作符優先順序的情況下,會出現錯誤。那現在對此進行修正,將宏 ceil_div 的參數用括弧進行包圍:
#define ceil_div(x, y) ((x) + (y) - 1) / (y)
使用這個定義,就能得到上面期望的結果。但是僅僅只是對宏參數加括弧,仍然在一些情況下會有問題,比如像下面使用宏 ceil_div:
sizeof ceil_div(1, 2)
宏被擴展之後,會成為下面的情形:
sizeof ((1) + (2) - 1) / (2)
由於 sizeof 的優先順序比算術運算符 / 的優先順序高,因此實際上是先進行 sizeof 的運算,再進行除法運算,即:
sizeof (((1) + (2) - 1)) / (2)
而期望的結果是先求宏的值,然後再進行 sizeof 運算:
sizeof (((1) + (2) - 1) / (2))
想要得到正確結果的修改也很簡單,直接將整個宏定義使用括弧包圍即可:
#define ceil_div(x, y) (((x) + (y) - 1) / (y))
因此,宏的參數以及宏定義加括弧,是為了解決操作符優先順序的問題。