Artificial truth

The more you see, the less you believe.

[archives] [latest] | [homepage] | [atom/rss]

MIN and MAX macro considered harmful
Tue 17 February 2015 — download

This is one of my favourite interview question: What is wrong with this macro ?

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

I mean, it's in the GNU libc, so it should be pretty good:

grep MIN /usr/include/sys/param.h 
#define MIN(a,b) ((a)<(b))?(a):(b))

Let me show you

#include <stdio.h>

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

int main() {
    int a = 1, b = 2;
    printf ("%d\n", min (a, b));
    printf ("a=%d, b=%d\n\n", a, b);

    printf ("%d\n", min (a++, b++));
    printf ("a=%d, b=%d\n\n", a, b);
$ gcc test.c && ./a.out
a=1, b=2

a=3, b=3


It's a classic trick: Double evaluation.

This is why cool kids are using this macro:

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

or even this one

#define MIN(x,y) ({ \
    typeof(x) _x = (x);     \
    typeof(y) _y = (y);     \
    (void) (&_x == &_y);    \
    _x < _y ? _x : _y; })

Unfortunately, it's using some cancer GNU extension; there is no way in ANSI C to get the type of a variable.

Of course, you could hardcode them (Or pass them as arguments, but this would be annoying (and you'll likely end using the GNU-specific statement as expressions extension, or worse, the blocks one)):

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

But since you're losing macro's genericity, you might as well use an inline function like this one

inline int min(int a, int b) {
    if (a > b)
        return b;
    return a;

Long story short: Don't use macro for MIN and MAX in C, because you'll use them one day with a side-effect argument, and then, Smokey, my friend, you will be entering a world of pain.

edit: It seems that this blogpost may make its way into cppcheck ;)