13 ответов:
где
MINиMAXопределяется в C, если вообще?это не так.
каков наилучший способ реализовать их, как можно более обобщенно и безопасно для типа (предпочтительны расширения компилятора/встроенные модули для основных компиляторов).
как функции. Я бы не стал использовать макросы типа
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), особенно если вы планируете развернуть свой код. Либо напишите свой собственный, используйте что-то вроде стандартногоfmaxилиfmin, или исправить макрос с помощью тип GCC (вы также получаете бонус за безопасность типа):#define max(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ _a > _b ? _a : _b; })все говорят: "о, я знаю о двойной оценке, это не проблема", и через несколько месяцев вы будете отлаживать самые глупые проблемы в течение нескольких часов подряд.
обратите внимание на использование
__typeof__вместоtypeof:если вы пишете заголовочный файл, который должен работать при включении в ISO С программы, пишите
__typeof__вместоtypeof.
Это также предусмотрено в версиях SYS/param для GNU libc (Linux) и FreeBSD.h, и имеет определение, предоставленное 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++), Я сомневаюсь, что когда-либо есть большая потребность в проверке максимума увеличенных значений за один раз. Сначала увеличьте, а затем проверьте.
это поздний ответ, из-за довольно недавнее развитие. Поскольку ОП принял ответ, который опирается на непереносимую ССЗ (и 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'sauto. Он не может (или не стоит?) используется в коде C++, хотя нет веских причин не использовать возможности вывода превосходного типаautoпри использовании C++11.что сказал, я предположим нет никаких проблем с использованием этого синтаксиса, когда макрос включен в
extern "C" { ... }объем; например, из заголовка c. AFAIK, это расширение не нашел свой путь информация 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; }тип безопасный, и никаких проблем с++, упомянутых в других комментариях.
стоит отметить, что я думаю, что если вы определяете
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(а-ля#include <windows.h>) иmaxиmin(нижний регистр) макросы, которые также страдают от "двойной оценки" трудности, но они есть для тех, кто не хочет перебрасывать свои :)
максимум два целых числа
aиbи(int)(0.5((a+b)+abs(a-b))). Это также может работать с(double)иfabs(a-b)для двойников (аналогично для поплавков)
самый простой способ-определить его как глобальную функцию в
.hфайл, и вызвать его, когда вы хотите, если ваша программа является модульной с большим количеством файлов. Если нет, тоdouble MIN(a,b){return (a<b?a:b)}Это самый простой способ.
Comments