简体   繁体   中英

The best way to define a “between” macro in C

What's the best way to define a between macro, which is type generic (char,int,long) which will return true if a number is between to other numbers inputted. I'm tried to google it, but I didn't find anything.

Edit: The order of the two boundaries given shouldn't matter. so it can be more general.

If you do something like:

#define BETWEEN(a, b, c)  (((a) >= (b)) && ((a) <= (c)))

you are going to have problem with the double evaluation of a . Think what would happens if you do that with a functions that has side effects...

you should instead do something like:

#define BETWEEN(a, b, c) ({ __typeof__ (a) __a = (a); ((__a) >= (b) && ((__a) <= (c)) })

(edited because the result should not depend of the order of b and c):

#define BETWEEN(a, b, c) \
           ({ __typeof__ (a) __a = (a);\
              __typeof__ (b) __b = (b);\
              __typeof__ (c) __c = (c);\
               (__a >= __b && __a <= __c)||\
               (__a >= __c && __a <= __b)})

Firstly, don't use macros for things like this - use functions (possibly inline).

Secondly, if you must use macros, then what's wrong with eg

#define BETWEEN(x, x_min, x_max) ((x) > (x_min) && (x) < (x_max))

?

As per your subsequent edit, if you don't know the ordering of x_min and x_max then you could do this:

#define BETWEEN2(x, x0, x1) (BETWEEN((x), (x0), (x1)) || \
                             BETWEEN((x), (x1), (x0)))

The usual caveats about macros and side-effects etc apply. Edit: removed space between macro & arguments for compilation

If all types are the same, how about:

/* Check if 'a' is between 'b' and 'c') */
#define BETWEEN(a, b, c)  (((a) >= (b)) && ((a) <= (c)))

Note that if the types of a , b and c above are different, the implicit type conversions of C might make it wrong. Especially if you mix signed and unsigned numbers.

If I understand correctly, you will need 3 numbers, the upper limit, the lower limit and the number you're checking, so I would do it like this:

#define BETWEEN(up, low, n) ((n) <= (up) && (n) >= (low))

This assumes the between is inclusive of the upper and lower limits, otherwise:

#define BETWEEN(up, low, n) ((n) < (up) && (n) > (low))

+1: A not-so-trivial question, since it involves the problem of the evaluation of macro parameters. The naive solution would be

#define BETWEEN(x,l1,l2) (((x) >= (l1)) && ((x) <= (l2)))

but "x" is evaluated twice, so there may be problems if the expression has side effects. Let's try something smarter:

#define BETWEEN(x,l1,l2) (((unsigned long)((x)-(l1))) <= (l2))

Very very tricky and not so clean, but...

#define BETWEEN_MIN(a, b) ((a)<(b) ? (a) : (b))
#define BETWEEN_MAX(a, b) ((a)>(b) ? (a) : (b))

#define BETWEEN_REAL(val, lo, hi) (((lo) <= (val)) && ((val) <= (hi)))
#define BETWEEN(val, hi, lo) \
      BETWEEN_REAL((val), BETWEEN_MIN((hi), (lo)), BETWEEN_MAX((hi), (lo)))

See code running: http://ideone.com/Hb1vP

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM