C语言中的MIN和MAX定义在哪里?

实现这些最好的方法是什么,尽可能的泛型和类型安全?(主流编译器的编译器扩展/内置优先。)


当前回答

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

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

其他回答

在c++中有std::min和std::max,但是在C标准库中没有等价的。你可以自己用宏来定义它们

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

但是,如果您编写MAX(++a, ++b)这样的代码,就会出现问题。

最简单的方法是将它定义为.h文件中的一个全局函数,如果您的程序是包含大量文件的模块化程序,则可以随时调用它。如果不是,double MIN(a,b){return (a<b?a:b)}是最简单的方法。

我将避免同时将MIN和MAX定义为预处理器宏。 即使改进了实现,避免了双重评估,即。

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

当您尝试在函数之外使用此函数(参见这里的示例)或在此答案中引用的变量阴影时,您会遇到其他问题,例如编译器错误。

如果你迫切需要宏所带来的性能优势,即代码内联,可以将它们实现为内联函数。大多数现代编译器都支持内联。比如像这样

inline int32_t MAX(int32_t a, int32_t b) { return((a) > (b) ? a : b); }
inline int32_t MIN(int32_t a, int32_t b) { return((a) < (b) ? a : b); }

(更多)

你必须为你需要的每一种数据类型实现一个变体,但通常你会使用有限的一组数据类型。话虽如此,请记住比较浮点数有它自己的怪癖,你需要比上面更复杂的代码(参见这里的讨论)。

@David Titarenco在这里写得很好,但至少让我把它清理一下,让它看起来更漂亮,并同时显示min()和max(),以便从这里复制和粘贴。:)

2020年4月25日更新:我还增加了第3节,以展示如何使用c++模板来实现这一点,对于那些同时学习C和c++,或从一个过渡到另一个的人来说,这是一个有价值的比较。我已经尽我所能做到全面、真实和正确,使这个答案成为我可以反复使用的权威参考,我希望你能和我一样觉得它有用。

1. 旧的C宏方式:

这种技术是常用的,受到那些知道如何正确使用它的人的尊重,这是一种“事实上”的做事方式,如果使用得当,使用起来很好,但如果你传递包含变量赋值的表达式来进行比较,就会出现bug(想想:双重求值的副作用):

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

2. 改进后的gcc和clang“语句表达式”方式:

这种技术避免了上述“双重计算”的副作用和错误,因此被认为是更好、更安全、“更现代”的GCC C方法。期望它能与gcc和clang编译器一起工作,因为clang在设计上是与gcc兼容的(请参阅答案底部的clang注释)。

但是:仍然要注意“变量阴影”效果,因为语句表达式显然是内联的,因此没有自己的局部变量作用域!

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

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

注意,在gcc语句表达式中,代码块中的最后一个表达式是表达式“返回”的表达式,就像从函数返回一样。GCC的文档是这样说的:

复合语句的最后一个东西应该是一个带分号的表达式;这个子表达式的值作为整个构造的值。(如果在大括号内使用其他类型的语句,则构造的类型为void,因此实际上没有值。)

3.[c++专用]c++模板方式:

注意:如果使用c++,这种类型的构造可能推荐使用模板,但我个人不喜欢模板,可能会在c++中使用上述构造之一,因为我经常在嵌入式c++中使用并更喜欢C样式。

新增2020年4月25日:

在过去的几个月里,我一直在做大量的c++,在c++社区中,更喜欢模板而不是宏的压力是相当大的。因此,我在使用模板方面做得越来越好,为了完整起见,我想在这里加入c++模板版本,使它成为一个更规范、更全面的答案。

下面是c++中max()和min()的基本函数模板版本:

template <typename T>
T max(T a, T b)
{
    return a > b ? a : b;
}

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

在这里阅读有关c++模板的更多信息:Wikipedia: Template (c++)。

然而,max()和min()已经是c++标准库的一部分,在<algorithm>标头中(#include <algorithm>)。在c++标准库中,它们的定义与上面的略有不同。std::max<>()和std::min<>()的默认原型,例如,在c++ 14中,在上面的cplusplus.com链接中查看它们的原型是:

template <class T> 
constexpr const T& max(const T& a, const T& b);

template <class T> 
constexpr const T& min(const T& a, const T& b);

注意,关键字typename是类的别名(所以无论你说<typename T>还是<class T>,它们的用法都是相同的),因为在c++模板发明之后,模板类型可能是常规类型(int, float等),而不仅仅是类类型。

Here you can see that both of the input types, as well as the return type, are const T&, which means "constant reference to type T". This means the input parameters and return value are passed by reference instead of passed by value. This is like passing by pointers, and is more efficient for large types, such as class objects. The constexpr part of the function modifies the function itself and indicates that the function must be capable of being evaluated at compile-time (at least if provided constexpr input parameters), but if it cannot be evaluated at compile-time, then it defaults back to a run-time evaluation, like any other normal function.

constexpr c++函数的编译时特性使它有点像C-宏,因为如果constexpr函数可以在编译时求值,那么它将在编译时完成,就像在C或c++中MIN()或MAX()宏替换也可能在编译时完全求值一样。有关此c++模板信息的其他参考资料,请参见下面。

4. [c++ only] c++ std::max()

如果使用c++,我想在<algorithm>头文件中添加内置的std::max()函数具有多种形式。请参阅cppreference.com社区wiki (https://en.cppreference.com/w/cpp/algorithm/max)文档页面上的“可能实现”部分,了解std::max()的4种形式的4种可能实现。

正常用法包括:

std::max(100, 200);

...但如果你想一次比较多个数字,你可以使用第四种形式,它接受std::initializer_list<T>,就像这样:

函数声明:

template< class T, class Compare >
constexpr T max( std::initializer_list<T> ilist, Compare comp );

用法:

// Compare **3 or more numbers** by passing a curly-brace-initialized
// `std::initializer_list<>` to `std::max()`!:

std::max({100, 200, 300});                  // result is 300
std::max({100, 200, 300, 400});             // result is 400
std::max({100, 200, 300, 400, 500});        // result is 500
std::max({100, 200, 300, 400, 500, 600});   // result is 600
// etc.

引用:

https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs C中的MIN和MAX 2020年4月新增c++模板参考: *****维基百科:模板(c++) <——伟大的额外信息关于c++模板! (我自己的问题和回答):为什么' constexpr '是' std::max() '的c++ 14模板原型的一部分? constexpr和const的区别是什么?

来自维基百科的提示:

[Clang]被设计为GNU编译器集合(GCC)的临时替代品,支持其大多数编译标志和非官方语言扩展。

相关:

[我的答案]舍入整数除法(而不是截断)——这里我也使用宏、gcc/clang语句表达式和c++模板。

两个整数a和b的最大值是(int)(0.5((a+b)+abs(a-b)))。这也可以用于(double)和fabs(a-b)用于double(类似于float)