MIN和MAX在C
C和MIN
定义在哪里?
实现这些目标的最好方法是什么?尽可能安全地进行安全操作? (主stream编译器的编译器扩展/内置首选。)
C和
MIN
定义在哪里?
他们不是。
什么是最好的方式来实现这些,尽可能一般和types安全(主stream编译器的编译器扩展/内置首选)。
作为功能。 我不会像#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
那样使用macros,特别是如果您打算部署代码。 要么写自己的,使用像标准fmax
或fmin
,或使用海湾合作委员会的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::min
和std::max
,但是AFAIK在C标准库中没有等价物。 你可以像macros一样自己定义它们
#define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y))
但是,如果你写了像MAX(++a, ++b)
这样的话会导致问题。
我不认为他们是标准化的macros。 浮点数已经有了标准函数, fmax
和fmin
(浮点数的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_float
macros也会被扩展,尽pipe它与int
无关。 而且由于这个macros有意地只包含float
types,所以代码将不会被编译。
为了解决这个问题,我使用##运算符在预处理器阶段创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安全,并没有问题与其他评论中提到的++。
值得指出的是,我认为如果你用第三级定义min
和max
,如
#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)
两个整数a
和b
的最大值是(int)(0.5((a+b)+abs(ab)))
。 这可能也适用于(double)
和fabs(ab)
双打(类似的花车)
看起来像Windef.h
(一个la #include <windows.h>
)有max
和min
(小写)的macros,这也是“双重评估”的困难,但他们在那里不希望重新推出自己的:)