2014-01-23 54 views
5

爲了獲得最大的兩個數字,我有以下宏以下哪個宏是安全的,爲什麼?

#define max(a,b) ((a) > (b) ? (a) : (b)) 

#define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) 

是什麼都上方的區別。哪一個更好用,爲什麼。我發現這些宏的信息here。但無法理解它。

+5

想想用max(++ i, - j)'來預處理器產生了什麼。 *既不*是「安全的」,但後者不像宏觀參數擴展那樣容易產生副作用。 – WhozCraig

+0

其次更安全。例如調用'max(i ++,j ++)'或者就此而言,'max(fn1(),fn2())' – anishsane

+2

請注意,這些宏中的第二個使用'gcc'擴展(將塊語句視爲表達式)並且因此不便攜。 – templatetypedef

回答

7

第二個宏是安全的,但使用由海灣合作委員會提供的非標準C擴展會發生什麼:statement expressions。但第一個表達是「通用」。使用typeof擴展GCC將有助於:

#define mymax(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); \ 
         _a > _b ? _a : _b; }) 

要針對JaredPar's answer提出的問題打,你可以使用預處理concatenation和GCC具體__COUNTER__(或僅僅是較爲標準__LINE__),例如

#define mymax_counted(a,b,c) ({typeof(a) _a##c = (a); \ 
           typeof(b) _b##c = (b); \ 
           _a##c > _b##c ? _a##c : _b##c; }) 
#define mymax(a,b) mymax_counted(a,b,__COUNTER__) 

但即使這樣也不是完全失效的證明(與壞運氣,能像mymax(_a123,_b123)一些調用衝突如果唯一__COUNTER__恰好是123當時)。

事實上,使用inline function更好(因爲如果你調用mymaxfun(i++,t[i])的行爲是明確界定,並給出了相同的結果mymaxfun(t[i],i++),因爲優化編譯器會產生代碼爲高效使用宏時):

static inline int mymaxfun(int a, int b) { return (a>b)?a:b; } 

不幸的是,C沒有通用功能(考慮將其切換爲C++及其templates並使用std::max);然而C11具有使用_Generic關鍵字

宏是非常有用(掌握時)類型的通用表達式,但調用宏時,你應該非常小心副作用的參數(如mymax(i++,t[--i]++)),所以你總是應該關心和文件如果名稱是一個宏或其他東西(如函數)。作爲一個經驗法則,避免副作用 - 在函數調用查找表達式(包括函數調用和宏調用)中,也包括++--以及其他許多其他函數。

查看源代碼的預處理器擴展形式;因此對於foo.c源代碼,運行gcc -C -E foo.c > foo.i(添加諸如-I,-D等的任何預處理器選項都是相關的),並在foo.iless foo.i;它總是有啓發性的。

+0

唯一的問題是當有人試圖用漂浮物來使用它。 – woolstar

6

第二個宏更安全,因爲它只對輸入進行一次評估。如果輸入是具有副作用的表達式,這一點很重要

max(i++, --j); 

請注意,我說的更安全和不安全。這個宏仍然有可能是不正確的,因爲可能有當地人在範圍內已經命名爲_a_ b。試想一下,如果下面是執行

int _a = 42; 
int _b = 13; 
maxint(_a, _b); 

這將拓展出

int _a = 42; 
int _b = 13; 
{int _a = (_a), _b = (_b); _a > _b ? _a : _b; }) 
+1

好的一點,雖然我注意到這是一個非常不好的編程習慣,爲了這個確切的原因開始一個帶下劃線的局部變量。 –

2

兩者都不安全。請避免使用非標準C擴展如表達式語句的宏實現,如果您需要將代碼移植到其他平臺,將會給您帶來各種麻煩。盡我所能從成爲一個咆哮來表達這個答案,在我看來,max宏是C標準庫中最糟糕的事情之一,因爲它有潛在的副作用。在過去,我已經#undef ed max只是爲了安全起見。

您最好將第二個宏maxint編碼爲一個函數,因爲它具有宏的所有缺點(例如,不容易調試,實例化的變量與本地衝突)但沒有任何好處(例如泛化)。

替代

我最喜歡的:使用三元在線:a > b ? a : b您可以放置​​在括號的味道,因爲你知道到底是怎麼回事。它也會比通過獲取價值副本來嘗試安全的宏更快。

構建您自己的功能。考慮爲整數類型定義max併爲浮點定義fmaxabsfabs已經有了先例。

+0

AFAIK,'max'不在C標準庫中...... –