一、簡述
記--請定義一個宏,求兩個數的最大值。
二、測試例子
2.1 例子1
測試代碼:
#include <stdio.h>
#define MAX(x,y) x>y?x:y
int main(int argc, char* argv[])
{
int maxVal = MAX(2,5);
printf("maxVal is %d.\n", maxVal);
return 0;
}
測試結果:
存在問題:含運算符的參數的宏展開後,因爲運算符優先級導致運算順序改變
#include <stdio.h>
#define MAX(x,y) x>y?x:y
int main(int argc, char* argv[])
{
int maxVal = MAX(1==1,1==2);//MAX(1,0)
printf("maxVal is %d.\n", maxVal);
return 0;
}
結果並非是我們所預料的1:
預編譯文件:gcc maxMacro.c -o maxMacro.i -E
運算符">"優先級高於運算符"==",因此1==1>1==2?1==1:1==2等價於1==(1>1)==2?1==1:1==2 --> 先進行計算1>1爲假即0;然後計算1==1,結果爲1;接着計算1==2,結果爲0;所以最後的結果是1==2爲0。
2.2 例子2
爲了防止例子1中的問題,我們給宏的參數加上小括號。
測試代碼:
#include <stdio.h>
#define MAX(x,y) (x)>(y)?(x):(y)
int main(int argc, char* argv[])
{
int maxVal = MAX(1==1,1==2);
printf("maxVal is %d.\n", maxVal);
return 0;
}
測試結果:
存在問題:在表達式中宏展開後,因爲宏外面的運算符優先級導致運算順序改變
#include <stdio.h>
#define MAX(x,y) (x)>(y)?(x):(y)
int main(int argc, char* argv[])
{
int maxVal = 2 + MAX(3,4);
printf("maxVal is %d.\n", maxVal);
return 0;
}
結果並非是我們所預料的2+4=6:
預編譯文件:
在宏所在的表達式中所含有的運算符'+'的優先級比運算符'>'要高,所以2 + (3)>(4)?(3):(4)等價於(2 + (3))>(4)?(3):(4) -->先進行計算2+3=5,5>4爲真,所以結果是3。
2.3 例子3
爲了防止例子2中的問題,我們給整個宏加上小括號。
測試代碼:
#include <stdio.h>
#define MAX(x,y) ((x)>(y)?(x):(y))
int main(int argc, char* argv[])
{
int maxVal = 2 + MAX(3,4);
printf("maxVal is %d.\n", maxVal);
return 0;
}
測試結果:
存在問題:自增自減運算符導致宏參數進行二次自增自減。
#include <stdio.h>
#define MAX(x,y) ((x)>(y)?(x):(y))
int main(int argc, char* argv[])
{
int x = 2;
int y = 5;
int maxVal = MAX(x++,y++);
printf("maxVal is %d.Now x is %d, y is %d.\n", maxVal, x, y);
return 0;
}
結果並非是我們所預料的5,(後++:先運算後自加1):圖示
預編譯文件:
將表達式((x++)>(y++)?(x++):(y++)) 拆分爲3個步驟:
步驟1:判斷(x++)>(y++)
2>5爲假,結果爲0,此時x=3,y=6
步驟2:此時表達式爲 0?x++:y++ (經過步驟1,此時的x=3,y=6)
取的是後面的值y,並且先用後加,因此表達式的值爲6
步驟3:y進行自加1,表達式計算完畢後,x的值是3,y的值是7.
2.4 例子4
爲了防止例子3中的問題,我們給使用臨時變量。
測試代碼:
#include <stdio.h>
#define MAX(x,y) ({\
int _x = x;\
int _y = y;\
_x>_y?_x:_y;\
})
int main(int argc, char* argv[])
{
int x = 2;
int y = 5;
int maxVal = MAX(x++,y++);
printf("maxVal is %d.\n", maxVal);
return 0;
}
測試結果:
2.5 例子5
適配不同數據類型
測試代碼:
#include <stdio.h>
#define MAX(type,x,y) ({\
type _x = x;\
type _y = y;\
_x>_y?_x:_y;\
})
int main(int argc, char* argv[])
{
int x = 2;
int y = 5;
int maxVal_int = MAX(int,x,y);
printf("maxVal_int is %d.\n", maxVal_int);
double d1 = 3.14;
double d2 = 9.527;
double maxVal_double = MAX(double,d1,d2);
printf("maxVal_double is %lf.\n", maxVal_double);
return 0;
}
測試效果:
2.6 例子6
在使用宏的時候無需指定參數數據類型,在宏內自動獲取參數數據類型。
GNU C 擴展了一個關鍵字 typeof,用來獲取一個變量或值的類型。
測試代碼:
#include <stdio.h>
#define MAX(x,y) ({\
typeof(x) _x = x;\
typeof(y) _y = y;\
_x>_y?_x:_y;\
})
int main(int argc, char* argv[])
{
int x = 2;
int y = 5;
int maxVal_int = MAX(x,y);
printf("maxVal_int is %d.\n", maxVal_int);
double d1 = 3.14;
double d2 = 9.527;
double maxVal_double = MAX(d1,d2);
printf("maxVal_double is %lf.\n", maxVal_double);
return 0;
}
測試結果:
2.7 例子7
對參數數據類型進行檢測,當不一致時給出警告信息,以提醒使用者。
測試代碼:
#include <stdio.h>
#define MAX(x,y) ({\
typeof(x) _x = x;\
typeof(y) _y = y;\
(void)(&_x == &_y);\
_x>_y?_x:_y;\
})
int main(int argc, char* argv[])
{
int x = 2;
double y = 5;
int maxVal_int = MAX(x,y);
printf("maxVal_int is %d.\n", maxVal_int);
return 0;
}
測試結果:
三、總結
3.2 以下情況需要考慮宏的整體性
1) 宏包含變量的定義。
2) 宏包含多個語句。
3.2 保證宏的整體性
({...})保證了宏的整體性
還有以下方式:
do{...}while(0) (這種方式不能作爲左值和右值,否則編譯不通過)