MIN和MAX在C

C和MIN定义在哪里?

实现这些目标的最好方法是什么?尽可能安全地进行安全操作? (主stream编译器的编译器扩展/内置首选。)

C和MIN定义在哪里?

他们不是。

什么是最好的方式来实现这些,尽可能一般和types安全(主stream编译器的编译器扩展/内置首选)。

作为功​​能。 我不会像#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))那样使用macros,特别是如果您打算部署代码。 要么写自己的,使用像标准fmaxfmin ,或使用海湾合作委员会的typeof (你也得到types安全奖金)修复macros:

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

每个人都说:“哦,我知道双重评估,这是没有问题的”,几个月后,你将会连续几个小时来debugging最难的问题。

请注意使用__typeof__而不是typeof

如果你正在写一个包含在ISO C程序中的头文件,写下__typeof__而不是typeof

它也在GNU libc(Linux)和FreeBSD版本的sys / param.h中提供,并具有由dreamlax提供的定义。


在Debian上:

 $ uname -sr Linux 2.6.11 $ cat /etc/debian_version 5.0.2 $ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) $ head -n 2 /usr/include/sys/param.h | grep GNU This file is part of the GNU C Library. 

在FreeBSD上:

 $ uname -sr FreeBSD 5.5-STABLE $ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) 

源代码库在这里:

  • GNU C库
  • FreeBSD的

在C ++中有一个std::minstd::max ,但是AFAIK在C标准库中没有等价物。 你可以像macros一样自己定义它们

 #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 

但是,如果你写了像MAX(++a, ++b)这样的话会导致问题。

我不认为他们是标准化的macros。 浮点数已经有了标准函数, fmaxfmin (浮点数的fmaxl ,长双精度的fmaxl )。

只要您意识到副作用/双重评估的问题,就可以将它们实现为macros。

 #define MAX(a,b) ((a) > (b) ? a : b) #define MIN(a,b) ((a) < (b) ? a : b) 

在大多数情况下,您可以将其留给编译器来确定您正在尝试执行的操作,并尽可能优化它。 虽然这会导致像MAX(i++, j++)一样的使用问题,但是我怀疑在一次检查增量值的最大值时是非常需要的。 先增加,然后检查。

我写的这个版本适用于MSVC,GCC,C和C ++。

 #if defined(__cplusplus) && !defined(__GNUC__) # include <algorithm> # define MIN std::min # define MAX std::max //# define TMIN(T, a, b) std::min<T>(a, b) //# define TMAX(T, a, b) std::max<T>(a, b) #else # define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \ ({ \ decltype(lexpr) lvar = (lexpr); \ decltype(rexpr) rvar = (rexpr); \ lvar binoper rvar ? lvar : rvar; \ }) # define _CHOOSE_VAR2(prefix, unique) prefix##unique # define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique) # define _CHOOSE(binoper, lexpr, rexpr) \ _CHOOSE2( \ binoper, \ lexpr, _CHOOSE_VAR(_left, __COUNTER__), \ rexpr, _CHOOSE_VAR(_right, __COUNTER__) \ ) # define MIN(a, b) _CHOOSE(<, a, b) # define MAX(a, b) _CHOOSE(>, a, b) #endif 

避免使用非标准的编译器扩展,并将其作为纯标准C(ISO 9899:2011)中完全types安全的macros实现。

 #define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y)) #define ENSURE_int(i) _Generic((i), int: (i)) #define ENSURE_float(f) _Generic((f), float: (f)) #define MAX(type, x, y) \ (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y)) 

用法

 MAX(int, 2, 3) 

说明

macrosMAX根据type参数创build另一个macros。 这个控制macros,如果为给定的types执行,用于检查这两个参数是正确的types。 如果该type不受支持,则会出现编译器错误。

如果x或y不是正确的types, ENSURE_macros中将会出现编译器错误。 如果支持更多的types,可以添加更多这样的macros。 我认为只有算术types(整数,浮点数,指针等)将被使用,而不是结构或数组等。

如果所有types都是正确的,GENERIC_MAXmacros将被调用。 在每个macros参数周围需要额外的括号,这是编写Cmacros时通常的标准预防措施。

那么C中的隐式types升级通常会遇到问题。 ?:运算符将第二个和第三个操作数相互平衡。 例如, GENERIC_MAX(my_char1, my_char2)结果是int 。 为了防止macros从事这种潜在危险types的促销活动,使用了最终的types转换为预期的types。

合理

我们希望macros的两个参数都是相同的types。 如果其中一个属于不同的types,那么这个macros就不再是types安全的了,因为象?:这样的运算符会产生隐式的types提升。 而且因为这样做,我们也总是需要把最后的结果回到上面所说的预期types。

只有一个参数的macros可以用更简单的方式写出来。 但有2个或更多的参数,需要包含一个额外的types参数。 因为这样的事情不幸是不可能的:

 // this won't work #define MAX(x, y) \ _Generic((x), \ int: GENERIC_MAX(x, ENSURE_int(y)) \ float: GENERIC_MAX(x, ENSURE_float(y)) \ ) 

问题是,如果上面的macros被调用MAX(1, 2)与两个int ,它仍然会尝试macros扩展_Generic关联列表的所有可能的情况。 所以ENSURE_floatmacros也会被扩展,尽pipe它与int无关。 而且由于这个macros有意地只包含floattypes,所以代码将不会被编译。

为了解决这个问题,我使用##运算符在预处理器阶段创buildmacros名称,以避免意外扩展macros。

例子

 #include <stdio.h> #define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y)) #define ENSURE_int(i) _Generic((i), int: (i)) #define ENSURE_float(f) _Generic((f), float: (f)) #define MAX(type, x, y) \ (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y)) int main (void) { int ia = 1, ib = 2; float fa = 3.0f, fb = 4.0f; double da = 5.0, db = 6.0; printf("%d\n", MAX(int, ia, ib)); // ok printf("%f\n", MAX(float, fa, fb)); // ok //printf("%d\n", MAX(int, ia, fa)); compiler error, one of the types is wrong //printf("%f\n", MAX(float, fa, ib)); compiler error, one of the types is wrong //printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong //printf("%f\n", MAX(float, da, db)); compiler error, one of the types is wrong //printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either //printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either return 0; } 

由于最近的发展,这是一个迟到的答案。 由于OP接受依赖于不可移植的GCC(和clang)扩展types或者__typeof__作为“干净的”ISO C的答案,所以gcc-4.9有更好的解决scheme。

 #define max(x,y) ( \ { __auto_type __x = (x); __auto_type __y = (y); \ __x > __y ? __x : __y; }) 

这个扩展的明显好处是每个macros参数只扩展一次,不像__typeof__解决scheme。

__auto_type是C ++ 11的一个有限forms。 它不能(或不应该)用在C ++代码中,尽pipe在使用C ++ 11的时候没有理由不使用auto的高级types推断function。

这就是说,我认为当macros被包含在extern "C" { ... }范围内时,使用这个语法没有问题; 例如来自C头。 AFAIK,这个扩展没有find它的方式信息铿锵

如果你需要最小/最大值以避免昂贵的分支,你不应该使用三元运算符,因为它会编译为一个跳转。 下面的链接描述了一个实现min / max函数而不分支的有用方法。

http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax

我知道这个人说“C”…但是如果你有机会,使用C ++模板:

 template<class T> T min(T a, T b) { return a < b ? a : b; } 

types安全,并没有问题与其他评论中提到的++。

值得指出的是,我认为如果你用第三级定义minmax ,如

 #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) 

那么为了得到相同的结果fmin(-0.0,0.0)fmax(-0.0,0.0)的特殊情况下,您需要交换参数

 fmax(a,b) = MAX(a,b) fmin(a,b) = MIN(b,a) 

两个整数ab的最大值是(int)(0.5((a+b)+abs(ab))) 。 这可能也适用于(double)fabs(ab)双打(类似的花车)

看起来像Windef.h (一个la #include <windows.h> )有maxmin (小写)的macros,这也是“双重评估”的困难,但他们在那里不希望重新推出自己的:)