在没有双重评估的情况下在Clang中实现min()和max()

min函数的经典预处理器版本看起来像

 #define min(a, b) ((a) < (b) ? (a) : (b)) 

这使你可以进行双重评估 – 你做min(f(), g()) ,忘记fg有副作用,你必须花费数小时试图找出你的函数运行两次的原因。 为了防止这种情况,你可以做到

 #define min(a, b) ({__typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ _a < _b ? _a : _b;}) 

这在GCC下工作得很好,但是如果你通过-Wgnu设置的Clang运行它 – 这组警告属于-pedantic的保护伞 – 你会得到像

 test.c:5:10: error: use of GNU statement expression extension [-Werror,-Wgnu] int a = min(3, 7); ^ test.c:1:22: note: expanded from macro 'min' # define min(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b); _a < _b ? _a : _b;}) 

是否有可能以防止双重评估的方式定义这些宏, 并且可以接受Clang under -pedantic ? (是的,你可以用-Wno-gnu禁用警告,在这种情况下,Clang处理语句表达没有问题。我问,因为我像clang -pedantic ,对我自己的好处太挑剔了。)

编辑:我在C工作。我也标记了这个C ++,因为我认为解决方案可能适用于C ++以及C.哎呀 – 忘了模板! 抱歉模棱两可。

如果你真的用C ++编写,那么就不要使用预处理器

 template  const T min(const T& a, const T& b) { return (b < a) ? b : a; } 

(注意我已经交换了ba ,所以如果两者相等,你就得到左手操作数。)

否则不,不是真的 。

我认为这可以作为C11解决方案。

 inline int min(int const x, int const y) { return y < x ? y : x; } inline unsigned minu(unsigned const x, unsigned const y) { return y < x ? y : x; } inline long minl(long const x, long const y) { return y < x ? y : x; } inline unsigned long minul(unsigned long const x, unsigned long const y) { return y < x ? y : x; } inline long long minll(long long const x, long long const y) { return y < x ? y : x; } inline unsigned long long minull(unsigned long long const x, unsigned long long const y) { return y < x ? y : x; } inline float minf(float const x, float const y) { return y < x ? y : x; } inline double mind(double const x, double const y) { return y < x ? y : x; } inline long double minld(long double const x, long double const y) { return y < x ? y : x; } #define MIN(X, Y) (_Generic((X) + (Y), \ int: min, \ unsigned: minu, \ long: minl, \ unsigned long: minul, \ long long: minll, \ unsigned long long: minull, \ float: minf, \ double: mind, \ long double: minld)((X), (Y))) 

Simple发布的C11解决方案看起来很理想,但是如果你没有C11编译器,你仍然可以定义一个具有内在类型安全性的宏(因为无论如何都像C一样安全):

 #define MIN(type, X, Y) min_ ## type(X, Y) 

此宏将仅允许传递已实现的类型,否则您将收到编译器错误。

例:

 #define MIN(type, X, Y) min_ ## type(X, Y) long min_long (long x, long y); char min_char (char x, char y); float min_float (float x, float y); int main() { long min_l = MIN (long, 5L, 10L); char min_c = MIN (char, 'A', 'B'); float min_f = MIN (float, 666.66f, 3.14f); printf("%ld\n", min_l); printf("%c\n", min_c); printf("%f\n", min_f); } char min_char (char x, char y) { return x < y ? x : y; } long min_long (long x, long y) { return x < y ? x : y; } float min_float (float x, float y) { return x < y ? x : y; } 

现在,如果你用MIN(int, 1, 2)执行上面的宏,你会得到一个编译器错误:“ min_int ,不存在这样的函数”。