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
и fmin
(и fmaxf
для поплавков, и 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)}
Это самый простой способ.