407

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

a3f
  • 8,517
  • 1
  • 41
  • 46
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526

16 Answers16

509

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.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
David Titarenco
  • 32,662
  • 13
  • 66
  • 111
  • 84
    You know, it'd be quite handy if gcc had a warning along the lines of: `warning: expression with side-effects multiply evaluated by macro` at the point of use... – caf Aug 09 '10 at 05:28
  • 29
    @caf: wouldn't that require that the preprocessor have a more complicated knowledge of C syntax? – dreamlax Aug 09 '10 at 05:34
  • 1
    @dreamlax: I was thinking that the preprocessor could leave annotations behind at the point of each macro expansion when a parameter was used more than once, which the compiler could then use. – caf Aug 09 '10 at 06:45
  • For the win, can you link to, or provide details for how to achieve this on Visual-C++? – Matt Joiner Aug 09 '10 at 08:50
  • Or any other C compiler that is not GCC? – Nordic Mainframe Aug 09 '10 at 09:50
  • 3
    After much trying to figure out, I don't think there's anyway to do this in VC++, but your best best is to try to mess with MSVC++ 2010 new `decltype` keyword -- but even so, Visual Studio can't do compound statements in macros (and `decltype` is C++ anyway), i.e. GCC's `({ ... })` syntax so I'm pretty sure it's not possible, anyway. I haven't looked at any other compilers regarding this issue, sorry Luther :S – David Titarenco Aug 10 '10 at 06:08
  • @caf, what you're asking for seems like it could be equivalent to the halting problem. Just because an expression *appears* multiple times doesn't mean it gets *evaluated* multiple times. Not to say that you couldn't, in principle, teach GCC to have a useful warning, albeit imperfect! – Bernd Jendrissek Jan 16 '13 at 01:55
  • @BerndJendrissek: Certainly there would be some cases where you couldn't expect GCC to know (eg. `#define FOO(i, j, k) ((i ? i : k) + (j ? j : k))` called as `FOO(a, b, c++)` where the program logic otherwise ensures that `a` and `b` are never both zero. But there would be many cases where it is unambiguous, and in the cases where it is ambiguous you could either say nothing or warn that it "may" be problematic. – caf Jan 16 '13 at 02:14
  • @DavidTitarenco your reasoning for not defining it as a macro is beyond me, but Visual Studio's stdlib.h defines it as a macro. Interestingly enough, the "intellisense" that checks your code as you type thinks it's undefined, and I got a C2059 error (which made no sense at first) trying to write my own function. – darda Feb 22 '14 at 15:08
  • 2
    See also http://stackoverflow.com/questions/5595593/min-macro-in-kernel-h - that is similar to this, but has an extra check for type safety. – user9876 May 06 '14 at 21:59
  • 11
    @dreamlax I once saw a case where someone had done `MAX(someUpperBound, someRandomFunction())` to limit a random value to some upper bound. It was a terrible idea, but it also didn't even work, because the `MAX` he was using had the double evaluation problem, so he ended up with a different random number than the one that was initially evaluated. – Zev Eisenberg Aug 12 '14 at 17:15
  • @NisseEngström Parentheses added for readability. Programmers shouldn't be expected to memorize the order of precedence for every language. I didn't change the number of underscores: I merely formatted it like code with backticks. If you think the number of underscores is wrong, change it yourself. – APerson Nov 02 '14 at 14:41
  • 3
    `warning: ISO C forbids braced-groups within expressions [-Wpedantic]` – Jeroen Ooms Apr 11 '15 at 06:51
  • 1
    What's wrong with #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) ? Can anyone please explain. Also, I have seen the use of typeof in many Linux macros. In what situations should I use them? Any reference material would be helpful. – Soumen Mar 11 '16 at 08:34
  • 1
    __typeof__ IMO most important part of this macro – Mazeryt Apr 13 '16 at 21:11
  • 17
    @Soumen For example, if you call `MIN(x++, y++)` the preprocessor will generate the following code `(((x++) < (y++)) ? (x++) : (y++))`. So, `x` and `y` will be incremented twice. – Antonio May 13 '16 at 14:51
  • Here I lined up text and added `min()` too for easier copying and pasting: https://stackoverflow.com/questions/3437404/min-and-max-in-c/58532788#58532788 – Gabriel Staples Oct 24 '19 at 01:09
  • 2
    @Antonio in MIN(x++,y++) say x is < y, then x would be incremented twice and y would be incremented only once. The '?' is a sequence point so all side-effects are resolved, and then only the one of the two statements separated by ':' is executed. – Vikas Yadav Jan 17 '20 at 06:26
  • 1
    @vikasyadav you are right, too bad I cannot correct my imprecise comment, only delete it – Antonio Jan 17 '20 at 14:13
  • `__typeof__` is standard C? Can't find it in the C11 standard... – Michael Beer Mar 05 '21 at 07:40
  • 1
    @MichaelBeer It's not, it's GCC. The line David quotes at the bottom is from https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Typeof.html#Typeof — `__typeof__` is provided specifically because `typeof` isn't permitted in ISO/ANSI C. – FeRD Aug 09 '21 at 07:04
  • @Antonio That's the least of your worries. It's also undefined behavior to increment a variable twice in the same expression, so you can't even conclude that the smaller variable gets incremented twice. – Ted Klein Bergman Nov 08 '21 at 13:53
  • To be clear, `__typeof__` and `typeof` are not yet part of standard C. – chux - Reinstate Monica May 22 '23 at 14:19
  • `typeof` is in C23 now. https://en.cppreference.com/w/c/language/typeof – Jeff Hammond Aug 01 '23 at 07:12
115

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:

Neuron
  • 5,141
  • 5
  • 38
  • 59
Mikel
  • 24,855
  • 8
  • 65
  • 66
  • I've added the definitions from the systems I have access to in my answer above (the comment field doesn't accept formatting as far as I can tell). Will try to find the links to the FreeBSD/Linux/glibc source repos. – Mikel Aug 15 '10 at 02:30
  • +1. Very nice. Works for `openSUSE/Linux 3.1.0-1.2-desktop`/`gcc version 4.6.2 (SUSE Linux)` too. :) Bad it's not portable. – Jack Jul 26 '12 at 18:08
  • Works on Cygwin too. – CMCDragonkai May 29 '17 at 17:51
  • 7
    Wait a moment. It doesn't prevent double evaluation, does it? :3 – user1857492 Nov 28 '17 at 15:37
114

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

dan04
  • 87,747
  • 23
  • 163
  • 198
  • 12
    why putting too much brackets??? I found a quiz where they said `#define MIN(A, B) ((A < B) ? A : B)` is not a flexible way, why??? –  Nov 04 '14 at 15:05
  • 110
    @Makouda: Extra parentheses in macros help to avoid operator precedence problems. For example, consider `#define MULT(x, y) x * y`. Then `MULT(a + b, a + b)` expands to `a + b * a + b`, which parses as `a + (b * a) + b` due to precedence. That's not what the programmer probably intended. – dan04 Nov 05 '14 at 01:09
  • 1
    that not needed when ?: has the lowest precedence anyway – wingerse Dec 06 '18 at 19:27
  • 6
    @WingerSendon: It doesn't; the comma operator does. – dan04 Jan 10 '19 at 23:22
  • 2
    But you can't pass an expression with comma operator as a parameter to a macro unless you parenthesize it anyway – Ruslan Feb 02 '21 at 20:28
40

@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.
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • 5
    what is the point of the huge section about c++ when this question asks about c? all it does is replicate what `std::max()` and `std::min()` already do. – qwr Jul 01 '20 at 21:51
  • 1
    @qwr: The point: 1) to learn, 2) to replicate what `std::max()` and `std::min()` already do, so you can understand how they work (to learn), 3) to learn C++ from C, since many people start with C and then need to learn C++ too, or vice versa, so having both the C and the C++ answer together is helpful for anyone who writes in both. Myself, for instance: I'm an embedded software engineer. Sometimes I work on C code bases, and I come here to copy and paste verbatim my macro or gcc statement expression answers, and sometimes I work in C++ code bases and read my notes here to remember templates. – Gabriel Staples Jul 01 '20 at 22:02
  • 1
    that is completely off-topic for this question – qwr Jul 01 '20 at 22:04
  • 5
    I wholeheartedly disagree: no answerer should be punished for going the extra mile and giving an answer more thorough than what is asked. Many people land on this page who are benefited by the extra information. But if you don't like it, close your eyes once you get to that part. Re-open them when you've sufficiently scrolled down the page. I made bold headings to make it clear when the C++ part starts, so one can easily ignore it if it is not applicable to their situation. – Gabriel Staples Jul 01 '20 at 22:05
  • You should probably write the template version as `min(T &&a, T &&b)`, so it can work faster if supplied rvalue references or lvaues. – user904963 Dec 27 '21 at 00:29
27

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;
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    That `GENERIC_MAX` macro is a bad idea by the way, you only have to try `GENERIC_MAX(var++, 7)` to find out why :-) Nowadays (especially with heavily optimising/inlining compilers), macros should pretty much be relegated to the simple forms only. The function-like ones are better as functions and the value-group ones better as enumerations. – paxdiablo Sep 27 '19 at 11:43
  • 1
    @paxdiablo Except _Generic function-like macros have better type safety than functions. As for anyone using horrible coding styles where `++` is mixed with other things in the same expression - well, that horrible coding style is their actual problem. It would however be possible to copy each parameter into a compound literal to avoid the multiple evaluations problem: `ENSURE_##type( (type){x} )` – Lundin Apr 14 '23 at 06:22
  • Interesting novel approach. Note that `MAX(float, fa, fb)` differs from `MAX(float, fa, fb)` when one of `fa, fb` is NAN. – chux - Reinstate Monica May 22 '23 at 14:29
  • @chux-ReinstateMonica For floating point numbers this whole thing is irrelevant anyway, since standard C got `fmax` etc functions at least since C99. – Lundin May 23 '23 at 06:49
24

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.

dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • This should be the preferred answer as there clearly are min and max functions in the math library : http://www.cplusplus.com/reference/cmath/fmax/ – imranal Jan 20 '16 at 17:55
  • @imranal What are you exactly speaking about? The *implementation* code of those library? But that code is not *exposed*, i.e. they are not placing it in the interface of the library, being potentially unsafe. – Antonio May 13 '16 at 14:53
  • 1
    @Antonio I think you are using incorrect definitions of "exposed" and "interface". The interface of a c library are the externed variables, types, macros, and function declarations in a header file; fmin/fmax are declared in the header file, so they are said to be exposed. I am not sure what you are referring to as unsafe though. – rationalcoder Jun 27 '16 at 00:28
23

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

Brett Hale
  • 21,653
  • 2
  • 61
  • 90
  • Kudos for recognising the macro problem but I'd still posit that a function would probably be better :-) – paxdiablo Sep 27 '19 at 11:44
  • @paxdiablo - I agree, though the question has the `c-preprocessor` tag. A function is not guaranteed to be inlined even with said keyword, unless using something like gcc's `__always_inline__` attribute. – Brett Hale Oct 02 '19 at 05:06
  • Related to [Brett Hale's comment](https://stackoverflow.com/a/32107675/2240756), `clang` started supporting `__auto_type` around 2016 (see [patch](https://reviews.llvm.org/D12686)). – Lars Feb 07 '19 at 15:21
  • 1
    This still uses the GCC (and clang) `({ ... })` extension. I don't think it's any more portable than the version with `typeof` (with or without underscores). – zwol Apr 29 '21 at 14:15
11

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
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • 3
    I upvoted but identifiers beginning with an underscore following by an uppercase letter are reserved. – dreamlax May 30 '16 at 05:10
8

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.

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

cib
  • 2,124
  • 2
  • 21
  • 23
  • 2
    If the compiler is smart enough it can avoid the branch – Axel Gneiting Nov 01 '11 at 22:38
  • 3
    If optimization is turned on, all modern compilers will emit a conditional move instead of a branch in most cases, so there is little point in using hacks like this. – Krzysztof Kosiński Mar 10 '15 at 15:15
  • 3
    Absolutely true, I have no idea what I was looking at back then, it's been a while. Both gcc and clang avoid branches with -O, both on x86 and armv7a. – cib Mar 11 '15 at 14:57
5

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

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
5

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)
Z boson
  • 32,619
  • 11
  • 123
  • 226
2

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.

cmdLP
  • 1,658
  • 9
  • 19
  • if you talk about old features then there are the [/\ (min) and `\/` (max) operators](https://retrocomputing.stackexchange.com/q/4965/1981) in older C – phuclv May 04 '22 at 03:39
1

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.

Bas Kuenen
  • 59
  • 1
  • 1
  • 16
    Arguments should be const references, you never know what user will pass. – nmikhailov Jun 12 '13 at 14:33
  • 9
    Such a function has already been standardised ([std::min](http://en.cppreference.com/w/cpp/algorithm/min)). – dreamlax Oct 02 '17 at 20:25
  • C++ have a lot of standard functions for most of the normal purposes, don't reinvent the wheel. However [MS also defines their own min/max](https://stackoverflow.com/q/11544073/995714) which sometimes causes problem – phuclv Jan 27 '19 at 02:54
0

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

qiaochu li
  • 25
  • 4
-1

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)

NRZ
  • 23
  • 1
  • 2
    I am not sure it works with non integers. Floating point math has nonlinear precision. – Treesrule14 Apr 09 '14 at 14:41
  • 1
    To expand on @Treesrule14's comment: This doesn't work because computers don't treat numbers the same way as mathematicians. Floating point has rounding issues, so you'd be unlikely to get the right answer. Even if you use integer maths, MAX_INT+MAX_INT gives -2, so max(MAX_INT, MAX_INT) using your formula would come out as -1. – user9876 Apr 28 '14 at 14:53
-4

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.

srezat
  • 1
  • 1
    @technosaurus It would be helpful if you described why this solution is wrong, not just that it is. – Tur1ng Apr 29 '19 at 15:28
  • @technosaurus, your response is really unhelpful. Tur1ing, it appears that the function is defined completely wrong (missing types on input params, missing semicolon after return statement), and converting int inputs to double is a poor way to do things, so the type should not be double. A define or statement expression would be better here (ex: [see here](https://stackoverflow.com/a/58532788/4561887)), but if a function, consider making one function to do this for int32_t types, one for uint32_t types, and one for float or double types, for a total of 3 different functions. – Gabriel Staples Oct 27 '19 at 22:13
  • 2
    @GabrielStaples This answer should be flagged as not an answer - there is no helping it. Although it could be used as an example of how to be the most wrong in the smallest amount of space. Recommending global functions in a header (not static inline even?) will break code with 2+ compilation units, doesn't even compile, naming a function like a macro, implied ints like its 1989, returning a double for no stated reason, implied casts that will cause warnings at best ... and most importantly IT DOESN'T ANSWER THE QUESTION - not generic, not type-safe and most definitely not the best way – technosaurus Oct 28 '19 at 00:08
  • 1
    Each one of those problems deserves further criticism that cannot be covered in sufficient detail. – technosaurus Oct 28 '19 at 02:32