2

The file windef.h defines the min/max functions using macros as follows:

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

It has been noted, however, that such a definition:

  1. Suffers from double evaluation.
  2. Is not type safe.

What I do not understand is:

  1. Why/where is there double evaluation?
  2. How does the trivial redefinition __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); helps with type safety and why is it not double evaluation in this case?
Sparkler
  • 2,581
  • 1
  • 22
  • 41
  • 8
    Think about `max(a++, b)` – Eugene Sh. Nov 03 '17 at 13:41
  • @EugeneSh. do you mean that the values entering are (a,b) but right after it's (a+1,b)? how is it related to type safety/double evaluation? – Sparkler Nov 03 '17 at 13:46
  • 1
    It will be `a+2`. Or try something like `max(printf("Hi!\n"), 5);`. – Eugene Sh. Nov 03 '17 at 13:49
  • 3
    @Sparkler Take EugeneSh's example a bit further: `max(f(a), b)` - what if `f` has a side effect, like creating a file or so. – Adam Kotwasinski Nov 03 '17 at 13:50
  • 1
    @Sparkler: `max(a++,b)` will expand to `(a++) > (b) ? (a++) : (b)` - `a++` is evaluated when comparing to `b`, and if the expression is true, will be evaluated again, so `a` gets incremented *twice*, which is probably not what you want. Remember that macros are just dumb text substitutions - macro arguments are not *evaluated* like function arguments, they're just expanded in place. – John Bode Nov 03 '17 at 14:46

1 Answers1

8

Why/where is there double evaluation?

The easiest way to understand this is to run this code:

#include <stdio.h>

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

int f1 (void) 
{ 
  printf("%s executed.\n", __func__);
  return 1; 
}

int f2 (void) 
{ 
  printf("%s executed.\n", __func__);
  return 2; 
}

int main (void)
{
  printf("Max: %d", max(f1(), f2()) );
}

Output:

f1 executed.
f2 executed.
f2 executed.
Max: 2

The function f2() is called twice, because the macro parameter b is evaluated twice.


How does the trivial redefinition __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); helps with type safety and why is it not double evaluation in this case?

Because that code creates two temporary variables and stores the result of the evaluation there, once per variable.

Please note that __typeof__ as well as the ({ ... }) syntax are not standard C and should be avoided. The macro from the linked accepted answer is quite ugly and not something I would recommend.

The sane solution is to not use a macro but a function:

static inline int max (int a, int b)
{
  return a > b ? a : b;
}

Notice how readable the code turns out, compared to the macro mess.

If you for some reason unknown must use macros, stick to standard C as shown here: https://stackoverflow.com/a/30918240/584518

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Re: "some reason unknown must use macros": A known difference of the `int max (int a, int b)` approach is that it forces the evaluation to `int` math whereas the macro approach does not. Of course this may or may not be important to to a given use case nor does this imply a macro is better. – chux - Reinstate Monica Nov 03 '17 at 14:27
  • 2
    @chux Indeed, the macro allows `max(apples, oranges)` :) – Lundin Nov 03 '17 at 14:58