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

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


当前回答

我知道那家伙说"C"… 但如果有机会,请使用c++模板:

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

类型安全,其他注释中提到的++没有问题。

其他回答

我知道那家伙说"C"… 但如果有机会,请使用c++模板:

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

类型安全,其他注释中提到的++没有问题。

值得指出的是,如果你用三元运算来定义最小值和最大值,比如

#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)

看起来像Windef.h (a la #include <windows.h>)有max和min宏(小写),这也遭受了“双重求值”的困难,但它们是为那些不想重新滚动自己的:)

@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++模板。

我将避免同时将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); }

(更多)

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