Мин и Макс в C



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



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

1023   13  

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 и fminfmaxf для поплавков, и 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's auto. Он не может (или не стоит?) используется в коде 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

    Ничего не найдено.