Макрос C минимум для двух чисел - PullRequest
4 голосов
/ 17 марта 2010

Я хочу сделать простой макрос с #define для возврата меньшего из двух чисел.

Как я могу сделать это в C? Предложите несколько идей и посмотрите, сможете ли вы сделать их более запутанными.

Ответы [ 7 ]

12 голосов
/ 17 марта 2010

Обычно:

#define min(a, b) (((a) < (b)) ? (a) : (b))

Имейте в виду, это оценивает минимум дважды, что и стало причиной катастрофы в недавнем вопросе .

Но почему вы хотите это скрыть?


Этот результат сохраняет результат в переменной и оценивает каждый аргумент только один раз. Это в основном встроенная функция бедного человека + объявление:

#define min(t, x, a, b) \
            t x; \
            { \
                t _this_is_a_unique_name_dont_use_it_plz_0_ = a; \
                t _this_is_a_unique_name_dont_use_it_plz_1_ = b; \
                x = _this_is_a_unique_name_dont_use_it_plz_0_ < \  
                    _this_is_a_unique_name_dont_use_it_plz_1_ ? \
                    _this_is_a_unique_name_dont_use_it_plz_0_ : \  
                    _this_is_a_unique_name_dont_use_it_plz_1_ ; \
            }

Используйте это как:

min(int, x, 3, 4)
/* x is an int, equal to 3
  Just like doing:

  int x = min(3, 4);

  Without double evaluation.
*/
5 голосов
/ 18 марта 2010

И, к черту, пример GNU C:

#define MAX(a,b) ({ \
    typeof(a) _a_temp_; \
    typeof(b) _b_temp_; \
    _a_temp_ = (a); \
    _b_temp_ = (b); \
    _a_temp_ = _a_temp_ < _b_temp_ ? _b_temp_ : _a_temp_; \
    })

Это не запутано, но я думаю, что это работает для любого типа, в любом контексте, на (почти, см. Комментарии) любых аргументах и ​​т.д .; пожалуйста, исправьте, если можете придумать какие-либо контрпримеры.

3 голосов
/ 20 марта 2010

Мне кажется, этот метод довольно симпатичный:

#define min(a, b) (((a) + (b) - fabs((a) - (b))) * 0.5)

3 голосов
/ 17 марта 2010

Конечно, вы можете использовать #define для этого, но зачем вам это? Проблема с использованием #define, даже с круглыми скобками, заключается в том, что вы получите неожиданный результат с кодом, подобным этому (хорошо, вы бы на самом деле этого не делали, но это иллюстрирует проблему).

int result = min(a++, b++);

Если вы используете C ++, а не C, безусловно, лучше использовать встроенную функцию, которая (i) избегает оценки параметров более одного раза и (ii) безопасна от типа (вы даже можете предоставить версии, принимающие другие типы значений). , как без знака, двойное или строковое).

inline int min(int a, int b) { return (a < b) ? a : b; }
1 голос
/ 19 сентября 2017

Я хочу сделать простой макрос с #define для возврата меньшего из двух чисел.

Я хотел добавить решение, когда числа равны с плавающей точкой .


Рассмотрим, когда числа являются числами с плавающей запятой, и одним из чисел является not-a-number . Тогда результат a < b всегда равен false независимо от значения другого числа.

// the result is `b` when either a or b is NaN
#define min(a, b) (((a) < (b)) ? (a) : (b))

Может быть желательно, чтобы результат был таким, как показано ниже, где «аргументы NaN обрабатываются как отсутствующие данные». С11 Сноска № 242

a NaN  |  b NaN  |  a < b  |  min
-------+---------+---------+---------------
No     |  No     |  No     |  b
No     |  No     |  Yes    |  a
No     |  Yes    |  .      |  a
Yes    |  No     |  .      |  b
Yes    |  Yes    |  .      |  either a or b

Чтобы сделать это с макросом в C, просто оберните функцию fmin(), которая поддерживает приведенную выше таблицу. Конечно, код должен обычно использовать функцию fmin() напрямую.

#include <math.h>
#define my_fmin(a, b) (fmin((a), (b))

Обратите внимание, что fmin(0.0, -0.0) может вернуть 0.0 или -0.0. Они оба имеют равное значение .

0 голосов
/ 20 марта 2010

Если бы я просто попытался слегка запутать это, я бы, вероятно, сказал что-то вроде:

#define min(a,b) ((a) + ((b) < (a) ? (b) - (a) : 0))

Я думаю, что решение Дойнакс тоже довольно милое. Обычное резервирование для обоих параметров макросов оценивается более одного раза.

0 голосов
/ 17 марта 2010

Для слегка запутанного, попробуйте это:

#define MIN(a,b)  ((((a)-(b))&0x80000000) >> 31)? (a) : (b)

По сути, он вычитает их и смотрит на бит знака как 1 или 0. Если вычитание приводит к отрицательному числу, первый параметр меньше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...