C 中的 MIN 和 MAX

发布于 2024-09-13 02:39:24 字数 117 浏览 4 评论 0 原文

C 中的 MINMAX 定义在哪里(如果有的话)?

实现这些的最佳方法是什么,尽可能通用并安全地输入? (首选主流编译器的编译器扩展/内置函数。)

Where are MIN and MAX defined in C, if at all?

What is the best way to implement these, as generically and type safely as possible? (Compiler extensions/builtins for mainstream compilers preferred.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

吲‖鸣 2024-09-20 02:39:24

C 中的 MINMAX 定义在哪里(如果有的话)?

他们不是。

实现这些的最佳方法是什么,尽可能通用且类型安全(首选主流编译器的编译器扩展/内置函数)。

作为函数。我不会使用像 #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) 这样的宏,特别是如果您计划部署您的代码。要么自己写,使用标准的 fmaxfmin,或修复使用 GCC 的 typeof 的宏(您将获得类型安全奖励也)在GCC语句表达式中:

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

每个人都说“哦,我知道双重评估,这没问题”,几个月后,您将连续几个小时调试最愚蠢的问题。

请注意使用 __typeof__ 而不是 typeof

如果您正在编写一个头文件
包含在 ISO C 中时必须有效
程序,写 __typeof__ 而不是
类型

Where are MIN and MAX defined in C, if at all?

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 fmax or fmin, or fix the macro using GCC's typeof (you get typesafety bonus too) in a GCC statement expression:

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

If you are writing a header file that
must work when included in ISO C
programs, write __typeof__ instead of
typeof.

天涯沦落人 2024-09-20 02:39:24

它也在 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))

源存储库位于:

It's also provided in the GNU libc (Linux) and FreeBSD versions of sys/param.h, and has the definition provided by dreamlax.


On 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:

$ 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:

酒几许 2024-09-20 02:39:24

C++ 中有 std::minstd::max,但据我所知,C 标准库中没有等效项。您可以使用类似这样的宏自行定义它们,

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

但是如果您编写类似 MAX(++a, ++b) 的内容,则会出现问题。

There's a std::min and std::max in C++, but AFAIK, there's no equivalent in the C standard library. You can define them yourself with macros like

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

放我走吧 2024-09-20 02:39:24

@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++ 中使用并更喜欢 C 样式。

本节添加于 2020 年 4 月 25 日:

在过去的几个月里,我一直在做大量的 C++ 工作,在 C++ 社区中,在可能的情况下,选择模板而不是宏的压力非常大。因此,我越来越擅长使用模板,并希望在此处放入 C++ 模板版本以保持完整性,并使之成为更规范和彻底的答案。

以下是 max()min() 的基本函数模板版本在 C++ 中的样子:

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++ 模板的内容:< a href="https://en.wikipedia.org/wiki/Template_(C%2B%2B)" rel="noreferrer">维基百科:模板 (C++)。

但是, max()min() 已经是 C++ 标准库的一部分,位于 < code> 标头 (#include )。在 C++ 标准库中,它们的定义与上面的定义略有不同。例如,在 C++14 中,std::max<>()std::min<>() 的默认原型,查看它们的上面 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);

请注意,关键字 typenameclass 的别名(因此,无论您说 >),因为后来在 C++ 模板发明后才承认,模板类型可能是常规类型( intfloat 等),而不仅仅是类类型。

这里您可以看到,输入类型和返回类型都是const T&,意思是“对类型T的常量引用”。这意味着输入参数和返回值是通过引用传递,而不是通过值传递。这就像传递指针一样,对于大型类型(例如类对象)更有效。函数的 constexpr 部分 修改函数本身并指示函数必须能够在编译时进行计算(至少如果提供了constexpr输入参数),但如果无法在编译时求值,则它默认返回运行时求值,就像任何其他普通函数一样。

constexpr C++ 函数的编译时方面使其类似于 C 宏,因为如果 constexpr 函数可以进行编译时评估,则它将在编译时完成,与 MIN()MAX() 宏替换相同,也可以在 C 或 C++ 中的编译时进行完全评估。有关此 C++ 模板信息的其他参考,请参阅下文。

4. [仅限 C++] C++ std::max()

如果使用 C++,我想添加内置的 std::max()函数有多种的形式。请参阅 cppreference.com 社区 wiki (https: //en.cppreference.com/w/cpp/algorithm/max),了解 4 种形式的 std::max() 的 4 种可能实现。

正常用法包括:

std::max(100, 200);

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

函数声明:

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.

引用:

  1. https://gcc.gnu .org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. C 中的 MIN 和 MAX
  4. 2020 年 4 月添加的其他 C++ 模板参考:
  5. *****维基百科:模板 (C++) <-- 有关 C++ 模板的更多附加信息!
  6. (我自己的问题和答案): 为什么 `constexpr` 是 `std::max()` 的 C++14 模板原型的一部分?
  7. constexpr 和 const 有什么区别?

Clang 注释 来自维基百科

[Clang] 旨在充当 GNU 编译器集合 (GCC) 的直接替代品,支持其大部分编译标志和非官方语言扩展。

相关:

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

@David Titarenco nailed it here, but let me at least clean it up a bit to make it look nice, and show both min() and max() together to make copying and pasting from here easier. :)

Update 25 Apr. 2020: I've also added a Section 3 to show how this would be done with C++ templates too, as a valuable comparison for those learning both C and C++, or transitioning from one to the other. I've done my best to be thorough and factual and correct to make this answer a canonical reference I can come back to again and again, and I hope you find it as useful as I do.

1. The old C macro way:

This technique is commonly used, well-respected by those who know how to use it properly, the "de facto" way of doing things, and fine to use if used properly, but buggy (think: double-evaluation side effect) if you ever pass expressions including variable assignment in to compare:

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

2. The new and improved gcc and clang "statement expression" way:

This technique avoids the above "double-evaluation" side effects and bugs, and is therefore considered the superior, safer, and "more modern" GCC C way to do this. Expect it to work with both the gcc and clang compilers, since clang is, by design, gcc-compatible (see the clang note at the bottom of this answer).

BUT: DO watch out for "variable shadowing" effects still, as statement expressions are apparently inlined and therefore do NOT have their own local variable scope!

#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;       \
})

Note that in gcc statement expressions, the last expression in the code block is what is "returned" from the expression, as though it was returned from a function. GCC's documentation says it this way:

The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)

3. [C++ only] The C++ template way:

C++ Note: if using C++, templates are probably recommended for this type of construct instead, but I personally dislike templates and would probably use one of the above constructs in C++ anyway, as I frequently use and prefer C styles in embedded C++ as well.

This section added 25 Apr. 2020:

I've been doing a ton of C++ the past few months, and the pressure to prefer templates over macros, where able, in the C++ community is quite strong. As a result, I've been getting better at using templates, and want to put in the C++ template versions here for completeness and to make this a more canonical and thorough answer.

Here's what basic function template versions of max() and min() might look like in C++:

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;
}

Do additional reading about C++ templates here: Wikipedia: Template (C++).

However, both max() and min() are already part of the C++ standard library, in the <algorithm> header (#include <algorithm>). In the C++ standard library they are defined slightly differently than I have them above. The default prototypes for std::max<>() and std::min<>(), for instance, in C++14, looking at their prototypes in the cplusplus.com links just above, are:

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

Note that the keyword typename is an alias to class (so their usage is identical whether you say <typename T> or <class T>), since it was later acknowledged after the invention of C++ templates, that the template type might be a regular type (int, float, etc.) instead of only a class type.

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.

The compile-time aspect of a constexpr C++ function makes it kind-of C-macro-like, in that if compile-time evaluation is possible for a constexpr function, it will be done at compile-time, same as a MIN() or MAX() macro substitution could possibly be fully evaluated at compile-time in C or C++ too. For additional references for this C++ template info, see below.

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

If using C++, I'd like to add that the built-in std::max() function in the <algorithm> header file has a variety of forms. See the "Possible implementation" section on the documentation page at the cppreference.com community wiki (https://en.cppreference.com/w/cpp/algorithm/max) for 4 possible implementations for the 4 forms of std::max().

Normal usages include:

std::max(100, 200);

...but if you'd like to compare many numbers at once, you can use the 4th form, which accepts a std::initializer_list<T>, like this:

Function declaration:

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

Usage:

// 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.

References:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. MIN and MAX in C
  4. Additional C++ template references added Apr. 2020:
  5. *****Wikipedia: Template (C++) <-- GREAT additional info about C++ templates!
  6. (My own question & answer): Why is `constexpr` part of the C++14 template prototype for `std::max()`?
  7. What's the difference between constexpr and const?

Clang note from Wikipedia:

[Clang] is designed to act as a drop-in replacement for the GNU Compiler Collection (GCC), supporting most of its compilation flags and unofficial language extensions.

Related:

  1. [my answer] Rounding integer division (instead of truncating) - I also use macros, gcc/clang statement expressions, and C++ templates here.
故人如初 2024-09-20 02:39:24

避免非标准编译器扩展,并将其实现为纯标准 C (ISO 9899:2011) 中完全类型安全的宏。

解决方案

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

说明

宏MAX根据type参数创建另一个宏。如果针对给定类型实现了该控制宏,则该控制宏用于检查两个参数的类型是否正确。如果不支持type,则会出现编译器错误。

如果 x 或 y 的类型不正确,ENSURE_ 宏中将会出现编译器错误。如果支持更多类型,可以添加更多此类宏。我假设仅使用算术类型(整数、浮点数、指针等),而不使用结构或数组等。

如果所有类型都正确,则将调用 GENERIC_MAX 宏。每个宏参数都需要额外的括号,这是编写 C 宏时通常的标准预防措施。

然后是 C 中隐式类型提升的常见问题。?:运算符平衡第二个和第三个操作数。例如,GENERIC_MAX(my_char1, my_char2) 的结果将是 int。为了防止宏执行此类潜在危险的类型提升,使用了最终类型转换为预期类型。

基本原理

我们希望宏的两个参数具有相同的类型。如果其中之一属于不同类型,则宏不再是类型安全的,因为像 ?: 这样的运算符将产生隐式类型提升。因为确实如此,我们也总是需要将最终结果转换回预期类型,如上所述。

只有一个参数的宏可以用一种更简单的方式编写。但如果有 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))  \
          )

问题是,如果上面的宏被调用为带有两个 intMAX(1, 2),它仍然会尝试宏 -展开_Generic关联列表的所有可能场景。因此,ENSURE_float 宏也会被扩展,即使它与 int 无关。由于该宏有意仅包含 float 类型,因此代码将无法编译。

为了解决这个问题,我在预处理器阶段使用 ## 运算符创建了宏名称,这样就不会意外扩展宏。

示例

#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;
}

Avoid non-standard compiler extensions and implement it as a completely type-safe macro in pure standard 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 type parameter. This control macro, if implemented for the given type, is used to check that both parameters are of the correct type. If the type is not supported, there will be a compiler error.

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.

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.

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.

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:

// 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 _Generic association list. So the ENSURE_float macro will get expanded too, even though it isn't relevant for int. And since that macro intentionally only contains the float type, the code won't compile.

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;
}
标点 2024-09-20 02:39:24

由于最近的发展,这是一个较晚的答案。由于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; })

此扩展的明显好处是每个宏参数仅扩展一次,与 __typeof__ 解决方案不同。

__auto_type 是 C++11 auto 的有限形式。它不能(或不应该?)在 C++ 代码中使用,尽管在使用 C++11 时没有充分的理由不使用 auto 的高级类型推断功能。

也就是说,我假设当宏包含在 extern "C" { ... } 作用域中时,使用此语法不会出现任何问题;例如,来自 C 标头。 AFAIK,这个扩展还没有找到它的方式 info clang

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.

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

__auto_type is 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 auto when using C++11.

That said, I assume there 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

一百个冬季 2024-09-20 02:39:24

我不认为它们是标准化的宏。浮点已经有了标准化函数,fmaxfmin(以及用于浮点的 fmaxf 和用于长整型的 fmaxl)双打)。

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

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

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

I don't think that they are standardised macros. There are standardised functions for floating point already, fmax and fmin (and fmaxf for floats, and fmaxl for long doubles).

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.

想念有你 2024-09-20 02:39:24

我写了这个版本 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

I wrote this version that works for MSVC, GCC, C, and 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
天生の放荡 2024-09-20 02:39:24

如果您需要最小/最大以避免昂贵的分支,则不应使用三元运算符,因为它会编译为跳转。 Bit Twiddling Hacks 描述了一种无需使用即可实现最小/最大函数的有用方法分枝。

int x; // 我们想要找到 x 和 y 的最小值
整数y;   
整数 r; // 结果放在这里 

r = y ^ ((x ^ y) & -(x < y)); // 最小值(x,y)

要查找最大值,请使用:

r = x ^ ((x ^ y) & -(x < y)); // 最大值(x,y)

快速而肮脏的版本:

如果您知道 INT_MIN <= x - y <= INT_MAX,那么您可以使用以下命令,这会更快,因为仅 (x - y)需要评估一次。

r = y + ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // 最小值(x,y)
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // 最大值(x,y)

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. Bit Twiddling Hacks describes a useful method for implementing a min/max function without branching.

int x;  // we want to find the minimum of x and y
int y;   
int r;  // the result goes here 

r = y ^ ((x ^ y) & -(x < y)); // min(x, y)

To find the maximum, use:

r = x ^ ((x ^ y) & -(x < y)); // max(x, y)

Quick and dirty versions:

If you know that INT_MIN <= x - y <= INT_MAX, then you can use the following, which are faster because (x - y) only needs to be evaluated once.

r = y + ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // min(x, y)
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)
尘世孤行 2024-09-20 02:39:24

值得指出的是,我认为如果您使用三元运算定义 minmax ,例如

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

then ,对于 fmin(- 0.0,0.0)fmax(-0.0,0.0) 您需要交换参数

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

It's worth pointing out I think that if you define min and max with the ternary operation such as

#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

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)
谷夏 2024-09-20 02:39:24

看起来像 Windef.h (类似于 #include )有 maxmin (小写)宏,也遭受“双重评估”困难,但它们是为那些不想重新推出自己的宏而存在的:)

Looks like Windef.h (a la #include <windows.h>) has max and 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 :)

温柔戏命师 2024-09-20 02:39:24

旧的 GCC 扩展:运算符 ?、?=

在非常旧的 GCC 版本中,有运算符 ? (请参阅此处,这里是 C++ 语言,但我认为当时它也作为 C 扩展应用)
我还看到了与赋值语句相对应的运算符?=

操作数被评估一次,甚至允许非常短的赋值语句。与常见的最小/最大分配相比,它非常短。没有什么可以超越这一点。

这些是以下内容的简写:

min(a, b)   ===   a < b ? a : b   ===   a <? b;
max(a, b)   ===   a > b ? a : b   ===   a >? b;
a = min(a, b);   ===   if(b < a) a = b;   ===   a <?= b;
a = max(a, b);   ===   if(b > a) a = b;   ===   a >?= b;

查找最小值非常简洁:

int find_min(const int* ints, int num_ints)
{
    assert(num_ints > 0);
    int min = ints[0];
    for(int i = 1; i < num_ints; ++i)
        min <?= ints[i];
    return min;
}

我希望有一天这可能会带回 GCC,因为我认为这些运算符非常天才。

Old GCC Extension: Operators <?, >?, <?=, >?=

In a very old version of GCC there were the operators <?, >? (see here, here it was in C++ but I think it also applied as a C extension back then)
I have also seen the operators <?=, >?= corresponding to the assignment statements.

The operands were evaluated once and even allowed for a very short assignment statement. Its very short compared to common min/max assignments. There is nothing that can top this.

Those were a shorthand for the following:

min(a, b)   ===   a < b ? a : b   ===   a <? b;
max(a, b)   ===   a > b ? a : b   ===   a >? b;
a = min(a, b);   ===   if(b < a) a = b;   ===   a <?= b;
a = max(a, b);   ===   if(b > a) a = b;   ===   a >?= b;

Finding the minimum is very concise:

int find_min(const int* ints, int num_ints)
{
    assert(num_ints > 0);
    int min = ints[0];
    for(int i = 1; i < num_ints; ++i)
        min <?= ints[i];
    return min;
}

I hope this might be some day brought back to GCC, because I think these operators are genious.

寻找我们的幸福 2024-09-20 02:39:24

正如其他答案所建议的,一个简单的解决方案是一个宏:

#define max(a, b) ((a) > (b) ? (a) : (b))

但是,这可能会导致意外结果和不必要的(如果 ab 是复杂表达式(有副作用)而不仅仅是变量,则重新计算。

该问题确实要求特定于编译器的扩展,因此其他答案也表明,更安全的选择是使用 GCC 语句表达式和 __typeof__ 。

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

如果您有 GCC,此解决方案非常有用。但否则根本不起作用。

如果您使用 C++,模板函数会更好。但问题被标记为 因此,仅 C++ 的答案并不适用于此处的所有情况。

我想提供一个便携式解决方案。由于 C 库已经具有以 lll 结尾的较大整数类型的函数,因此我们可以定义自己的 minmax< /code> 以同样的方式匹配库中找到的函数,例如 abs/absl/abslldiv< /code>/divl/divll

static inline int min(const int a, const int b) {
    return a < b ? a : b;
}
static inline int max(const int a, const int b) {
    return a > b ? a : b;
}
static inline long minl(const long a, const long b) {
    return a < b ? a : b;
}
static inline long maxl(const long a, const long b) {
    return a > b ? a : b;
}
static inline long long minll(const long long a, const long long b) {
    return a < b ? a : b;
}
static inline long long maxll(const long long a, const long long b) {
    return a > b ? a : b;
}

该解决方案是 GCC 扩展或仅 C++ 功能的良好替代品,并且比宏更安全。我们没有定义 fmin 和 < a href="https://en.cppreference.com/w/c/numeric/math/fmax" rel="nofollow noreferrer">fmax 及其浮点类型的变体因为那些已经存在了。

A simple solution as the other answers suggest would be a macro along the lines of:

#define max(a, b) ((a) > (b) ? (a) : (b))

However this can cause unexpected results and unnecessary (re)computation if a and b are complex expressions (with side effects) rather than just variables.

The question did ask for compiler-specific extensions so as the other answers also suggest, a safer option would be to use GCC statement expressions and __typeof__.

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

This solution is great if you have GCC. But will not work at all otherwise.

A template function would be even better if you are using C++. But the question is tagged so a C++ only answer does not apply to all cases here.

I would like to offer a portable solution. Since the C library already has functions ending in l and ll for larger integer types, we could define our own min and max the same way, to match the functions found in the library, such as abs/absl/absll and div/divl/divll.

static inline int min(const int a, const int b) {
    return a < b ? a : b;
}
static inline int max(const int a, const int b) {
    return a > b ? a : b;
}
static inline long minl(const long a, const long b) {
    return a < b ? a : b;
}
static inline long maxl(const long a, const long b) {
    return a > b ? a : b;
}
static inline long long minll(const long long a, const long long b) {
    return a < b ? a : b;
}
static inline long long maxll(const long long a, const long long b) {
    return a > b ? a : b;
}

This solution is a good substitute for GCC extensions or C++ only features, and is safer than macros. We do not define fmin and fmax and their variants for floating point types because those already exist.

宫墨修音 2024-09-20 02:39:24

我知道那个人说“C”...
但如果有机会,请使用 C++ 模板:

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

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

I know the guy said "C"...
But if you have the chance, use a C++ template:

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

Type safe, and no problems with the ++ mentioned in other comments.

宛菡 2024-09-20 02:39:24

在gcc中,你可以使用这个:

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

在msvc中,你可以使用这个:

#define SMART_MIN(x, y) \
    ([&]() -> decltype(x) { \
        decltype(x) _min1 = (x); \
        decltype(y) _min2 = (y); \
        return _min1 < _min2 ? _min1 : _min2; \
    })()

这样,可以确保x,y不会被计算2次

in gcc, you can use this:

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

in msvc, you can use this:

#define SMART_MIN(x, y) \
    ([&]() -> decltype(x) { \
        decltype(x) _min1 = (x); \
        decltype(y) _min2 = (y); \
        return _min1 < _min2 ? _min1 : _min2; \
    })()

in this way, can make sure x, y won't be calculated 2 times

心如荒岛 2024-09-20 02:39:24

两个整数 ab 的最大值为 (int)(0.5((a+b)+abs(ab)))。对于双精度数,这也可以与 (double)fabs(ab) 一起使用(与浮点数类似)

The maximum of two integers a and b is (int)(0.5((a+b)+abs(a-b))). This may also work with (double) and fabs(a-b) for doubles (similar for floats)

白云不回头 2024-09-20 02:39:24

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

The simplest way is to define it as a global function in a .h file, and call it whenever you want, if your program is modular with lots of files. If not, double MIN(a,b){return (a<b?a:b)} is the simplest way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文