The classic preprocessor version of the min
function looks like
#define min(a, b) ((a) < (b) ? (a) : (b))
This leaves you open to double evaluation—the situation in which you do min(f(), g())
, forgetting that f
or g
has side effects, and you have to spend hours trying to figure out why your function is running twice. To prevent this, you can do
#define min(a, b) ({__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b;})
This works great under GCC, but if you run it through Clang with -Wgnu
set—this set of warnings falls under the umbrella of -pedantic
—you get errors like
test.c:5:10: error: use of GNU statement expression extension [-Werror,-Wgnu]
int a = min(3, 7);
^
test.c:1:22: note: expanded from macro 'min'
# define min(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b); _a < _b ? _a : _b;})
Is it possible to define these macros in a way that prevents double evaluation and which is acceptable to Clang under -pedantic
? (Yes, you can disable the warning with -Wno-gnu
, in which case Clang handles the statement expression without a problem. I’m asking because I, like clang -pedantic
, am too picky for my own good.)
Edit: I am working in C. I tagged this C++ too because I thought a solution might apply to C++ as well as to C. Oops—forgot about templates! Sorry for the ambiguity.
I think this would work as a C11 solution.
inline
int min(int const x, int const y)
{
return y < x ? y : x;
}
inline
unsigned minu(unsigned const x, unsigned const y)
{
return y < x ? y : x;
}
inline
long minl(long const x, long const y)
{
return y < x ? y : x;
}
inline
unsigned long minul(unsigned long const x, unsigned long const y)
{
return y < x ? y : x;
}
inline
long long minll(long long const x, long long const y)
{
return y < x ? y : x;
}
inline
unsigned long long minull(unsigned long long const x, unsigned long long const y)
{
return y < x ? y : x;
}
inline
float minf(float const x, float const y)
{
return y < x ? y : x;
}
inline
double mind(double const x, double const y)
{
return y < x ? y : x;
}
inline
long double minld(long double const x, long double const y)
{
return y < x ? y : x;
}
#define MIN(X, Y) (_Generic((X) + (Y), \
int: min, \
unsigned: minu, \
long: minl, \
unsigned long: minul, \
long long: minll, \
unsigned long long: minull, \
float: minf, \
double: mind, \
long double: minld)((X), (Y)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With