Лучший способ определить макрос "между" в C - PullRequest
3 голосов
/ 28 ноября 2011

Какой лучший способ определить макрос между типами, который является типом generic (char, int, long), который будет возвращать true, если число находится между другими введенными числами.Я пытался гуглить, но ничего не нашел.

Редактировать: Порядок двух указанных границ не должен иметь значения.так что это может быть более общим.

Ответы [ 6 ]

4 голосов
/ 28 ноября 2011

Если вы сделаете что-то вроде:

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

, у вас будут проблемы с двойной оценкой a.Подумайте, что произойдет, если вы сделаете это с функциями, имеющими побочные эффекты ...

Вместо этого вы должны сделать что-то вроде:

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

(отредактировано, потому что результат не должен зависеть отпорядок b и 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)})
3 голосов
/ 28 ноября 2011

Во-первых, не используйте макросы для подобных вещей - используйте функции (возможно, встроенные).

Во-вторых, если вы должны использовать макросы, то что не так с, например,

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

Согласно вашему последующему редактированию, если вы не знаете порядок x_min и x_max, тогда вы можете сделать это:

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

Применяются обычные предостережения о макросах, побочных эффектах и ​​т. Д. Редактировать: убрал пробел между макросом и аргументами для компиляции

2 голосов
/ 28 ноября 2011

Если все типы одинаковы, как насчет:

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

Обратите внимание, что если типы a, b и c выше отличаются, неявные преобразования типов C могут сделать это неправильно. Особенно, если вы смешиваете числа со знаком и без знака.

1 голос
/ 28 ноября 2011
#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)))

См. Код работает: http://ideone.com/Hb1vP

1 голос
/ 28 ноября 2011

+ 1: нетривиальный вопрос, поскольку он затрагивает проблему оценки макропараметров. Наивное решение будет

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

но "x" вычисляется дважды, поэтому могут возникнуть проблемы, если выражение имеет побочные эффекты. Давайте попробуем что-нибудь умнее:

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

Очень хитрый и не очень чистый, но ...

1 голос
/ 28 ноября 2011

Если я правильно понимаю, вам понадобятся 3 числа, верхний предел, нижний предел и номер, который вы проверяете, поэтому я бы сделал это так:

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

Предполагается, что интервал включает верхний и нижний пределы, в противном случае:

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