9

I often find myself writing something like

int computedValue = ...;
return MAX(0, MIN(5, computedValue));

I would like to be able to write this as a single one-line macro. It must be free of side effects, in the same way that the existing system macros MIN and MAX are, and should work for the same data types as MIN and MAX.

Can anyone show me how to turn this into a single macro?

Micah Hainline
  • 14,367
  • 9
  • 52
  • 85
hfossli
  • 22,616
  • 10
  • 116
  • 130

5 Answers5

18

This is without side effects and works for any primitive number:

#define MIN(A,B)    ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
#define MAX(A,B)    ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })

#define CLAMP(x, low, high) ({\
  __typeof__(x) __x = (x); \
  __typeof__(low) __low = (low);\
  __typeof__(high) __high = (high);\
  __x > __high ? __high : (__x < __low ? __low : __x);\
  })

Can be used like so

int clampedInt = CLAMP(computedValue, 3, 7);
double clampedDouble = CLAMP(computedValue, 0.5, 1.0);

Other suggested names instead of CLAMP can be VALUE_CONSTRAINED_LOW_HIGH, BOUNDS, CLIPPED.

hfossli
  • 22,616
  • 10
  • 116
  • 130
3

Taken from this site http://developer.gnome.org/glib/2.34/glib-Standard-Macros.html#CLAMP:CAPS

#define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
hfossli
  • 22,616
  • 10
  • 116
  • 130
  • 2
    Oh, side effects. `CLAMP(getchar(), low++, high--)` – aragaer Feb 08 '13 at 10:02
  • That's right. Good point!!! So that's why we should do like this http://stackoverflow.com/questions/3437404/min-and-max-in-c/3437484#3437484 and not use the default MIN and MAX like @VosobeKapsimanis suggests. – hfossli Feb 08 '13 at 10:05
2

Maybe you want to try it like that:

template <class T> 
const T& clamp(const T& value, const T& low, const T& high) {
    return value < low ? low:
           value > high? high:
                         value;
}
Udo Klein
  • 6,784
  • 1
  • 36
  • 61
1
 #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 
 #define MIN(a, b) (((a) > (b)) ? (b) : (a))

making it in one #define directive isn't going to be very readable.

-1

Using just one compare operation:

static inline int clamp(int value, int min, int max) {
    return min + MIN((unsigned int)(value - min), max - min)
}
aragaer
  • 17,238
  • 6
  • 47
  • 49
  • Well. Say the type of the value can change - I would prefer a macro? Do you agree? – hfossli Feb 08 '13 at 09:56
  • Yeah, would require some way to make "unsigned typeof" to turn it into macro. – aragaer Feb 08 '13 at 09:59
  • On the other hand assuming we're working with integral types only, `#define CLAMP(x, low, high) ({ typeof(low) _low = (low); LARGE_ENOUGH_UNSIGNED_TYPE _x = (x) - _low, _high = (high) - _low; (typeof(x)) MIN(_x, _high); })` – aragaer Feb 08 '13 at 10:08