C语言 C 中的 MIN 和 MAX
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3437404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MIN and MAX in C
提问by Matt Joiner
Where are MINand MAXdefined in C, if at all?
如果有的话MIN,MAX在 C 中定义在哪里?
What is the best way to implement these, as generically and type safely as possible? (Compiler extensions/builtins for mainstream compilers preferred.)
实现这些的最佳方法是什么,尽可能通用和安全地键入?(首选主流编译器的编译器扩展/内置函数。)
回答by David Titarenco
Where are
MINandMAXdefined in C, if at all?
如果有的话
MIN,MAX在 C 中定义在哪里?
They aren't.
他们不是。
What is the best way to implement these, as generically and type safe as possible (compiler extensions/builtins for mainstream compilers preferred).
实现这些的最佳方法是什么,尽可能通用和类型安全(首选主流编译器的编译器扩展/内置)。
As functions. I wouldn't use macros like #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), especially if you plan to deploy your code. Either write your own, use something like standard fmaxor fmin, or fix the macro using GCC's typeof(you get typesafety bonus too) in a GCC statement expression:
作为函数。我不会使用像 那样的宏#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)),特别是如果你打算部署你的代码。要么自己编写,使用类似标准fmax或的东西fmin,要么在GCC 语句表达式中使用GCC 的 typeof(你也获得类型安全奖励)修复宏:
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
Everyone says "oh I know about double evaluation, it's no problem" and a few months down the road, you'll be debugging the silliest problems for hours on end.
每个人都说“哦,我知道双重评估,这没问题”,几个月后,您将连续数小时调试最愚蠢的问题。
Note the use of __typeof__instead of typeof:
注意使用__typeof__代替typeof:
If you are writing a header file that must work when included in ISO C programs, write
__typeof__instead oftypeof.
如果您正在编写一个必须在 ISO C 程序中包含的头文件,请
__typeof__使用typeof.
回答by Mikel
It's also provided in the GNU libc (Linux) and FreeBSD versions of sys/param.h, and has the definition provided by dreamlax.
它也在 sys/param.h 的 GNU libc (Linux) 和 FreeBSD 版本中提供,并且具有由 dreamlax 提供的定义。
On Debian:
在 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.
On FreeBSD:
在 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))
The source repositories are here:
源存储库在这里:
回答by dan04
There's a std::minand std::maxin C++, but AFAIK, there's no equivalent in the C standard library. You can define them yourself with macros like
在 C++ 中有一个std::minand std::max,但是 AFAIK,在 C 标准库中没有等价物。您可以使用宏自己定义它们,例如
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
But this causes problems if you write something like MAX(++a, ++b).
但是,如果您编写类似MAX(++a, ++b).
回答by Lundin
Avoid non-standard compiler extensions and implement it as a completely type-safe macro in pure standard C (ISO 9899:2011).
避免非标准编译器扩展,并在纯标准 C (ISO 9899:2011) 中将其实现为完全类型安全的宏。
Solution
解决方案
#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))
Usage
用法
MAX(int, 2, 3)
Explanation
解释
The macro MAX creates another macro based on the typeparameter. This control macro, if implemented for the given type, is used to check that both parameters are of the correct type. If the typeis not supported, there will be a compiler error.
宏 MAX 基于type参数创建另一个宏。此控制宏(如果为给定类型实现)用于检查两个参数的类型是否正确。如果type不支持,则会出现编译器错误。
If either x or y is not of the correct type, there will be a compiler error in the ENSURE_macros. More such macros can be added if more types are supported. I've assumed that only arithmetic types (integers, floats, pointers etc) will be used and not structs or arrays etc.
如果 x 或 y 的类型不正确,则ENSURE_宏中将出现编译器错误。如果支持更多类型,可以添加更多此类宏。我假设只使用算术类型(整数、浮点数、指针等),而不使用结构或数组等。
If all types are correct, the GENERIC_MAX macro will be called. Extra parenthesis are needed around each macro parameter, as the usual standard precaution when writing C macros.
如果所有类型都正确,将调用 GENERIC_MAX 宏。每个宏参数都需要额外的括号,作为编写 C 宏时通常的标准预防措施。
Then there's the usual problems with implicit type promotions in C. The ?:operator balances the 2nd and 3rd operand against each other. For example, the result of GENERIC_MAX(my_char1, my_char2)would be an int. To prevent the macro from doing such potentially dangerous type promotions, a final type cast to the intended type was used.
然后是 C 中隐式类型提升的常见问题。?:运算符平衡了第二个和第三个操作数。例如, 的结果GENERIC_MAX(my_char1, my_char2)将是int。为了防止宏执行此类具有潜在危险的类型提升,使用了对预期类型的最终类型转换。
Rationale
基本原理
We want both parameters to the macro to be of the same type. If one of them is of a different type, the macro is no longer type safe, because an operator like ?:will yield implicit type promotions. And because it does, we also always need to cast the final result back to the intended type as explained above.
我们希望宏的两个参数都是相同的类型。如果其中一个是不同的类型,宏就不再是类型安全的,因为像这样的运算符?:会产生隐式类型提升。正因为如此,我们也总是需要将最终结果转换回预期的类型,如上所述。
A macro with just one parameter could have been written in a much simpler way. But with 2 or more parameters, there is a need to include an extra type parameter. Because something like this is unfortunately impossible:
一个只有一个参数的宏可以用更简单的方式编写。但是对于 2 个或更多参数,需要包含一个额外的类型参数。因为不幸的是,这样的事情是不可能的:
// this won't work
#define MAX(x, y) \
_Generic((x), \
int: GENERIC_MAX(x, ENSURE_int(y)) \
float: GENERIC_MAX(x, ENSURE_float(y)) \
)
The problem is that if the above macro is called as MAX(1, 2)with two int, it will still try to macro-expand all possible scenarios of the _Genericassociation list. So the ENSURE_floatmacro will get expanded too, even though it isn't relevant for int. And since that macro intentionally only contains the floattype, the code won't compile.
问题是,如果上面的宏被调用为MAX(1, 2)with two int,它仍然会尝试宏扩展_Generic关联列表的所有可能场景。所以ENSURE_float宏也会被扩展,即使它与int. 由于该宏有意仅包含float类型,因此代码将无法编译。
To solve this, I created the macro name during the pre-processor phase instead, with the ## operator, so that no macro gets accidentally expanded.
为了解决这个问题,我在预处理器阶段使用 ## 运算符创建了宏名称,这样就不会意外扩展宏。
Examples
例子
#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;
}
回答by Brett Hale
This is a late answer, due to a fairly recent development. Since the OP accepted the answer that relies on a non-portable GCC (and clang) extension typeof- or __typeof__for 'clean' ISO C - there's a better solution available as of gcc-4.9.
由于最近的发展,这是一个迟到的答案。由于 OP 接受了依赖于非便携式 GCC(和 clang)扩展的答案typeof——或者__typeof__对于“干净的”ISO C——从gcc-4.9 开始,有一个更好的解决方案可用。
#define max(x,y) ( \
{ __auto_type __x = (x); __auto_type __y = (y); \
__x > __y ? __x : __y; })
The obvious benefit of this extension is that each macro argument is only expanded once, unlike the __typeof__solution.
与__typeof__解决方案不同,此扩展的明显好处是每个宏参数仅扩展一次。
__auto_typeis a limited form of C++11's auto. It cannot (or should not?) be used in C++ code, though there's no good reason not to use the superior type inference capabilities of autowhen using C++11.
__auto_type是 C++11 的有限形式auto。它不能(或不应该?)在 C++ 代码中使用,但没有充分的理由不使用auto使用 C++11 时的高级类型推断功能。
That said, I assumethere are no issues using this syntax when the macro is included in an extern "C" { ... }scope; e.g., from a C header. AFAIK, this extension has not found its way info clang
也就是说,当宏包含在范围内时,我认为使用此语法没有问题extern "C" { ... };例如,来自 C 头文件。AFAIK,这个扩展还没有找到它的方式信息叮当声
回答by dreamlax
I don't think that they are standardised macros. There are standardised functions for floating point already, fmaxand fmin(and fmaxffor floats, and fmaxlfor long doubles).
我不认为它们是标准化的宏。已经有浮点fmax和fmin(以及fmaxf浮点数和fmaxl长双精度数)的标准化函数。
You can implement them as macros as long as you are aware of the issues of side-effects/double-evaluation.
只要您知道副作用/双重评估的问题,您就可以将它们实现为宏。
#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)
In most cases, you can leave it to the compiler to determine what you're trying to do and optimise it as best it can. While this causes problems when used like MAX(i++, j++), I doubt there is ever much need in checking the maximum of incremented values in one go. Increment first, then check.
在大多数情况下,您可以将它留给编译器来确定您要尝试做什么并尽可能优化它。虽然这在使用时会导致问题MAX(i++, j++),但我怀疑是否有必要一次性检查增量值的最大值。先增加,再检查。
回答by Matt Joiner
I wrote this versionthat works for MSVC, GCC, C, and C++.
我编写的这个版本适用于 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
回答by cib
If you need min/max in order to avoid an expensive branch, you shouldn't use the ternary operator, as it will compile down to a jump. The link below describes a useful method for implementing a min/max function without branching.
如果您需要 min/max 以避免昂贵的分支,则不应使用三元运算符,因为它会编译为跳转。下面的链接描述了一种无需分支即可实现最小/最大函数的有用方法。
http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
回答by rogerdpack
Looks like Windef.h(a la #include <windows.h>) has maxand min(lower case) macros, that also suffer from the "double evaluation" difficulty, but they're there for those that don't want to re-roll their own :)
看起来Windef.h(a la #include <windows.h>)有max和min(小写)宏,它们也受到“双重评估”困难的影响,但它们适合那些不想重新推出自己的人:)
回答by Z boson
It's worth pointing out I think that if you define minand maxwith the tertiary such as
值得指出的是,我认为如果您定义min并max使用第三级,例如
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
then to get the same result for the special case of fmin(-0.0,0.0)and fmax(-0.0,0.0)you need to swap the arguments
然后为特殊情况获得相同的结果fmin(-0.0,0.0),fmax(-0.0,0.0)您需要交换参数
fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)

