巨集定義裡面為什麼要加括號?

chaoguo1234發表於2022-03-19

在巨集定義當中,常常可以看到巨集的引數以及整個巨集的定義都被小括號包圍,就像下面的 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))

 

因此,巨集的引數以及巨集定義加括號,是為了解決操作符優先順序的問題。

 

相關文章