development

C에서 MIN과 MAX

big-blog 2020. 3. 31. 08:21
반응형

C에서 MIN과 MAX


C에서 어디에 MIN있고 MAX정의되어 있습니까?

일반적으로 가능한 한 안전하게 입력하는 가장 좋은 방법은 무엇입니까? (주류 컴파일러를위한 컴파일러 확장 / 내장 선호)


C에서 어디에 MIN있고 MAX정의되어 있습니까?

그렇지 않습니다.

이를 구현하는 가장 좋은 방법은 일반적이고 가능한 한 안전합니다 (주류 컴파일러를위한 컴파일러 확장 / 기본 제공).

기능으로. #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))특히 코드를 배포하려는 경우 와 같은 매크로를 사용하지 않습니다 . 직접 작성하거나 standard 또는와 같은 것을 사용 fmax하거나 GCC의 typeof를fmin 사용하여 매크로를 수정하십시오 (유형 안전 보너스도 제공됨).

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

모두들 "오, 나는 이중 평가에 대해 알고있다. 아무 문제가 없다"고 말하고 몇 달 동안 길을 가다 보면 가장 어려운 문제들을 몇 시간 동안 디버깅 할 것이다.

__typeof__대신에 typeof다음을 사용하십시오 .

ISO C 프로그램에 포함될 때 작동해야하는 헤더 파일을 작성하는 경우 __typeof__대신 대신 작성하십시오 typeof.


또한 GNU libc (Linux) 및 FreeBSD 버전의 sys / param.h에서 제공되며 dreamlax에서 제공하는 정의를 가지고 있습니다.


데비안에서 :

$ 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))

소스 리포지토리는 다음과 같습니다.


C ++ 에는 a std::minstd::maxC가 있지만 C 표준 라이브러리에는 AFAIK가 없습니다. 다음과 같은 매크로로 직접 정의 할 수 있습니다

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

그러나 이와 같은 것을 쓰면 문제가 발생합니다 MAX(++a, ++b).


이것은 최근의 개발로 인해 늦은 답변입니다. OP가 이식 불가능한 GCC (및 클랜) 확장 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_typeC ++ 11의 제한된 형식입니다 auto. C ++ 코드에서는 autoC ++ 11 을 사용할 때의 우수한 형식 유추 기능을 사용하지 않을 이유가 없지만 C ++ 코드에서 사용할 수 없습니다 .

즉, 매크로가 범위에 포함될 때이 구문을 사용하는 데 문제가 없다고 가정 합니다 extern "C" { ... }. 예를 들어 C 헤더에서. AFAIK,이 확장 프로그램은 정보 clang을 찾지 못했습니다


비표준 컴파일러 확장을 피하고 순수 표준 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는 type매개 변수를 기반으로 다른 매크로를 만듭니다 . 지정된 유형에 대해 구현 된 경우이 제어 매크로는 두 매개 변수가 모두 올바른 유형인지 확인하는 데 사용됩니다. type지원되지 않으면 컴파일러 오류가 발생합니다.

x 또는 y가 올바른 유형이 아닌 경우 ENSURE_매크로에 컴파일러 오류가 발생 합니다. 더 많은 유형이 지원되는 경우 더 많은 매크로를 추가 할 수 있습니다. 나는 산술 유형 (정수, 부동 소수점, 포인터 등) 만 사용되며 구조체 또는 배열 등은 사용하지 않는다고 가정했습니다.

모든 유형이 올 바르면 GENERIC_MAX 매크로가 호출됩니다. C 매크로를 작성할 때 일반적인 표준주의 사항으로 각 매크로 매개 변수 주위에 추가 괄호가 필요합니다.

그런 다음 C에서 암시 적 유형 승격에 일반적인 문제점이 있습니다. ?:연산자는 두 번째와 세 번째 피연산자의 균형을 맞 춥니 다. 예를 들어 결과는 GENERIC_MAX(my_char1, my_char2)입니다 int. 매크로가 잠재적으로 위험한 유형 승격을 수행하지 못하게하기 위해 최종 유형이 의도 된 유형으로 캐스트되었습니다.

이론적 해석

매크로에 대한 두 매개 변수가 동일한 유형이 되길 원합니다. 그중 하나가 다른 유형 인 경우 매크로는 더 이상 유형 안전하지 않습니다. 같은 연산자 ?:는 암시 적 유형 승격을 생성 하기 때문 입니다. 그렇게하기 때문에, 우리는 또한 항상 최종 결과를 위에서 설명한대로 의도 된 유형으로 다시 변환해야합니다.

매개 변수가 하나만있는 매크로는 훨씬 간단한 방식으로 작성되었을 수 있습니다. 그러나 2 개 이상의 매개 변수를 사용하면 추가 유형 매개 변수를 포함해야합니다. 이와 같은 것은 불행히도 불가능하기 때문에 :

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

문제는 위의 매크로가 MAX(1, 2)two 로 호출 된 경우 int에도 _Generic연결 목록 의 가능한 모든 시나리오를 매크로 확장하려고 시도한다는 것 입니다. 따라서 ENSURE_float관련이 없어도 매크로가 확장됩니다 int. 그리고 그 매크로는 의도적으로 float유형 만 포함하기 때문에 코드는 컴파일되지 않습니다.

이를 해결하기 위해 ## 연산자를 사용하여 사전 프로세서 단계에서 매크로 이름을 만들어 실수로 매크로가 확장되지 않도록했습니다.

#include <stdio.h>

#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))

int main (void)
{
  int    ia = 1,    ib = 2;
  float  fa = 3.0f, fb = 4.0f;
  double da = 5.0,  db = 6.0;

  printf("%d\n", MAX(int,   ia, ib)); // ok
  printf("%f\n", MAX(float, fa, fb)); // ok

//printf("%d\n", MAX(int,   ia, fa));  compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib));  compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db));  compiler error, one of the types is wrong

//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
  return 0;
}

나는 그들이 표준화 된 매크로라고 생각하지 않습니다. 표준화 이미 부동 소수점을위한 기능이 있습니다 fmaxfmin(와 fmaxf수레를 위해, 그리고 fmaxl긴 복식은).

부작용 / 이중 평가 문제를 알고있는 한 매크로로 매크로를 구현할 수 있습니다.

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

대부분의 경우 컴파일러에 맡겨서 수행하려는 작업을 결정하고 최대한 최적화 할 수 있습니다. 이처럼 사용할 때 문제가 발생하지만 MAX(i++, j++)한 번에 최대 증가 값을 확인해야 할 필요성이 의심 스럽습니다. 먼저 증분 한 다음 확인하십시오.


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가 필요한 경우 삼항 연산자를 사용하면 안됩니다. 점프로 컴파일됩니다. 아래 링크는 분기없이 최소 / 최대 기능을 구현하는 유용한 방법을 설명합니다.

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


내가 생각에서 그 가치를 가리키는 것 당신이 정의하는 경우 그 minmax같은 차 등으로

#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>)가 maxmin(소문자) 매크로는 또한 "이중 평가"어려움으로 고통, 그러나 그렇지 않은 사람들을 위해 거기 있음을 다시 롤 자신 :) 원하는


나는 그 남자가 "C"라고 말한 것을 알고있다. 그러나 만약 당신이 기회가 있다면 C ++ 템플릿을 사용하라

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

다른 주석에서 언급 한 ++에는 문제가 없으며 안전합니다.


최대 2 개의 정수 a이며 b입니다 (int)(0.5((a+b)+abs(a-b))). 이것은 또한 작동 할 수 (double)fabs(a-b)복식 (수레 유사)


Brett Hale의 의견관련하여 2016 년경 clang부터 지원 __auto_type시작되었습니다 ( 패치 참조 ).


가장 간단한 방법은 .h파일 에서 전역 함수로 정의하고 프로그램이 많은 파일로 모듈 식인 경우 원할 때마다 호출하는 것입니다. 그렇지 않은 경우 double MIN(a,b){return (a<b?a:b)}가장 간단한 방법입니다.

참고 URL : https://stackoverflow.com/questions/3437404/min-and-max-in-c

반응형