C語言 請定義一個宏,求兩個數的最大值

一、簡述
    記--請定義一個宏,求兩個數的最大值。


二、測試例子

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) (這種方式不能作爲左值和右值,否則編譯不通過)
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章