MIN и MAX в C

где MIN и MAX определено в C, если вообще?

каков наилучший способ реализовать их, как можно более обобщенно и безопасно? (Предпочтительны расширения / встроенные компиляторы для основных компиляторов.)

13 ответов


где MIN и MAX определено в C, если вообще?

это не так.

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

как функции. Я бы не использовал макросы, такие как #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), особенно если вы планируете развернуть свой код. Либо напишите свой собственный, используйте что-то вроде standard fmax или fmin, или исправить макрос с помощью ССАГПЗ вызова typeof (вы получаете бонус typesafety тоже):

 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

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

обратите внимание на использование __typeof__ вместо typeof:

если вы пишете в файл заголовка, который должен работать при включении в ISO С программы, пишите __typeof__ вместо typeof.


это также предусмотрено в версиях GNU libc (Linux) и FreeBSD sys/param.ч и определение dreamlax.


На Debian:

$ uname -sr
Linux 2.6.11

$ cat /etc/debian_version
5.0.2

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

$ head -n 2 /usr/include/sys/param.h | grep GNU
This file is part of the GNU C Library.

На FreeBSD:

$ uname -sr
FreeBSD 5.5-STABLE

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

исходные репозитории находятся здесь:


здесь std::min и std::max в C++, но AFAIK, нет эквивалента в стандартной библиотеке C. Вы можете определить их самостоятельно с помощью макросов, таких как

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

но это вызывает проблемы, если вы пишете что-то вроде MAX(++a, ++b).


избегайте нестандартных расширений компилятора и реализуйте его как полностью типобезопасный макрос в чистом стандарте C (ISO 9899:2011).

решение

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

использование

MAX(int, 2, 3)

объяснение

макрос MAX создает другой макрос на основе


Я не думаю, что они стандартизованы макросы. Уже существуют стандартизированные функции для плавающей точки,fmax и fminfmaxf для поплавков, и fmaxl долго дубли).

вы можете реализовать их как макросы, пока вы знаете о проблемах побочных эффектов / двойной оценки.

#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)

в большинстве случаев, вы можете оставить его для компилятора, чтобы определить, что вы пытаетесь сделать и оптимизировать его как можно лучше. Хотя это вызывает проблемы при использовании как MAX(i++, j++), Я сомневаюсь, что когда-либо есть необходимость в проверке максимума увеличенных значений за один раз. Сначала увеличьте, затем проверьте.


это поздний ответ, из-за довольно недавнее развитие. Поскольку OP принял ответ, который полагается на непереносимое расширение GCC (и clang)typeof или __typeof__ для "чистого" ISO C-есть лучшее решение, доступное с gcc-4.9.

#define max(x,y) ( \
    { __auto_type __x = (x); __auto_type __y = (y); \
      __x > __y ? __x : __y; })

очевидным преимуществом этого расширения является то, что каждый аргумент макроса расширяется только один раз, в отличие от __typeof__ решение.

__auto_type является ограниченной формой c++11-х auto. Не может (или не должен?) использоваться в коде C++, хотя нет никаких оснований не использовать возможности вывода высшего типа auto при использовании C++11.

что сказал, я предположим нет проблем с использованием этого синтаксиса, когда макрос включен в extern "C" { ... } объем; например, из заголовка c. AFAIK, это расширение не нашло свой путь info clang


Я написал версия это работает для MSVC, GCC, C и c++.

#if defined(__cplusplus) && !defined(__GNUC__)
#   include <algorithm>
#   define MIN std::min
#   define MAX std::max
//#   define TMIN(T, a, b) std::min<T>(a, b)
//#   define TMAX(T, a, b) std::max<T>(a, b)
#else
#       define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \
                ({ \
                        decltype(lexpr) lvar = (lexpr); \
                        decltype(rexpr) rvar = (rexpr); \
                        lvar binoper rvar ? lvar : rvar; \
                })
#       define _CHOOSE_VAR2(prefix, unique) prefix##unique
#       define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique)
#       define _CHOOSE(binoper, lexpr, rexpr) \
                _CHOOSE2( \
                        binoper, \
                        lexpr, _CHOOSE_VAR(_left, __COUNTER__), \
                        rexpr, _CHOOSE_VAR(_right, __COUNTER__) \
                )
#       define MIN(a, b) _CHOOSE(<, a, b)
#       define MAX(a, b) _CHOOSE(>, a, b)
#endif

Если вам нужен min / max, чтобы избежать дорогостоящей ветви, вы не должны использовать тернарный оператор, так как он будет компилироваться до прыжка. В приведенной ниже ссылке описывается полезный метод реализации функции min / max без ветвления.

http://graphics.stanford.edu / ~seander / bithacks.html#IntegerMinOrMax


Я знаю, что парень сказал "С"... Но если у вас есть шанс, используйте шаблон C++:

template<class T> T min(T a, T b) { return a < b ? a : b; }

Type safe, и никаких проблем с++, упомянутым в других комментариях.


стоит отметить, я думаю, что если вы определите min и max С высших, таких, как

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

затем, чтобы получить тот же результат для особого случая fmin(-0.0,0.0) и fmax(-0.0,0.0) вам нужно поменять аргументы

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)

выглядит так:Windef.h (a la #include <windows.h>) и max и min (нижний регистр) макросы, которые также страдают от сложности "двойной оценки", но они существуют для тех, кто не хочет перекатывать свои собственные :)


максимум два целых числа a и b is (int)(0.5((a+b)+abs(a-b))). Это также может работать с (double) и fabs(a-b) для двойников (аналогично для поплавков)


самый простой способ-определить его как глобальную функцию в .h file и вызывайте его, когда захотите, если ваша программа модульная с большим количеством файлов. Если нет,double MIN(a,b){return (a<b?a:b)} Это самый простой способ.