I need to find the maximum and minimum of an arbitrary C expression which has no side effects. The following macros work on my machine. Will they work on all platforms? If not, can they be modified to work? My intent is to subsequently use these to implement macros like SAFE_MUL(a,b)
in place of a*b
. SAFE_MUL
would include a check for multiplication overflow.
EDIT: the type is cast as suggested by Steve.
#include <stdio.h>
#include <limits.h>
#define IS_SIGNED(exp) (((exp)*0-1) < 0)
#define TYPE_MAX_UNSIGNED(exp) ((exp)*0-1)
#define TYPE_MAX_SIGNED(exp) ( \
sizeof (exp) == sizeof (int) \
? \
INT_MAX \
: \
( \
sizeof (exp) == sizeof (long) \
? \
LONG_MAX \
: \
LLONG_MAX \
) \
)
#define TYPE_MAX(exp) ((unsigned long long)( \
IS_SIGNED (exp) \
? \
TYPE_MAX_SIGNED (exp) \
: \
TYPE_MAX_UNSIGNED (exp) \
))
#define TYPE_MIN_SIGNED(exp) ( \
sizeof (exp) == sizeof (int) \
? \
INT_MIN \
: \
( \
sizeof (exp) == sizeof (long) \
? \
LONG_MIN \
: \
LLONG_MIN \
) \
)
#define TYPE_MIN(exp) ((long long)( \
IS_SIGNED (exp) \
? \
TYPE_MIN_SIGNED (exp) \
: \
(exp)*0 \
))
int
main (void) {
printf ("TYPE_MAX (1 + 1) = %lld\n", TYPE_MAX (1 + 1));
printf ("TYPE_MAX (1 + 1L) = %lld\n", TYPE_MAX (1 + 1L));
printf ("TYPE_MAX (1 + 1LL) = %lld\n", TYPE_MAX (1 + 1LL));
printf ("TYPE_MAX (1 + 1U) = %llu\n", TYPE_MAX (1 + 1U));
printf ("TYPE_MAX (1 + 1UL) = %llu\n", TYPE_MAX (1 + 1UL));
printf ("TYPE_MAX (1 + 1ULL) = %llu\n", TYPE_MAX (1 + 1ULL));
printf ("TYPE_MIN (1 + 1) = %lld\n", TYPE_MIN (1 + 1));
printf ("TYPE_MIN (1 + 1L) = %lld\n", TYPE_MIN (1 + 1L));
printf ("TYPE_MIN (1 + 1LL) = %lld\n", TYPE_MIN (1 + 1LL));
printf ("TYPE_MIN (1 + 1U) = %llu\n", TYPE_MIN (1 + 1U));
printf ("TYPE_MIN (1 + 1UL) = %llu\n", TYPE_MIN (1 + 1UL));
printf ("TYPE_MIN (1 + 1ULL) = %llu\n", TYPE_MIN (1 + 1ULL));
return 0;
}
(exp)*0
is to get a0
cast to the type of (exp) subject to the constraint that the type of exp is not smaller than an int – UnderbidSAFE_MUL(a,b)
seems to be much more useful ifa
andb
aren't constants. – Laryngology(x+1) * y * z / (x + y)
, wherex, y, z
may themselves be arbitrary expressions. I expected an optimising compiler to be able to evaluateTYPE_MAX (exp1)
at compile time, regardless of the value ofx
,y
andz
. Having said that, I agree that the question is more general than what the example can handle, for 3 reasons (1 pointed out by steve): (1) exp consisting of unsigned constants smaller than int wont work. (2) exp involving float, double wont work. (3) The value returned byTYPE_MAX
may be lesser than the actual – Underbid