programing

C의 MIN과 MAX

prostudy 2022. 8. 2. 22:17
반응형

C의 MIN과 MAX

어디있나MIN그리고.MAXC에 정의되어 있습니까?

이것들을 가능한 한 일반적으로 안전하게 실장하는 가장 좋은 방법은 무엇입니까? (미드레인지 컴파일러용 확장자/빌트인)

어디있나MIN그리고.MAXC에 정의되어 있습니까?

그들은 아니에요.

가능한 한 일반적으로 안전한 타입으로 실장하는 최선의 방법은 무엇입니까(미드레인지 컴파일러용 확장자/빌트인)

기능으로서.저는 이런 매크로를 사용하지 않습니다.#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))특히 코드를 전개할 예정인 경우.직접 쓰거나 표준 또는 와 같은 것을 사용하거나 GCC표현에서 GCC의 타입 오브를 사용하여 매크로를 수정합니다(타입 안전 보너스도 받습니다).

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

모두가 "복수평가에 대해 알고 있습니다. 문제 없습니다."라고 말하고 몇 달 후, 여러분은 몇 시간 동안 계속해서 가장 어리석은 문제를 디버깅하게 될 것입니다.

의 사용에 주의해 주세요.__typeof__대신typeof:

ISO C 프로그램에 포함되어 있을 때 동작해야 하는 헤더 파일을 쓰는 경우,__typeof__대신typeof.

이 있습니다.std::min그리고.std::maxC++, 그러나 AFAIK에서는 C 표준 라이브러리에는 동등한 것이 없습니다.다음과 같은 매크로를 사용하여 직접 정의할 수 있습니다.

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

하지만 만약 당신이 다음과 같은 것을 쓴다면, 이것은 문제를 일으킨다.MAX(++a, ++b).

GNU libc(Linux) 및 FreeB에서도 제공됩니다.SD 버전sys/param.hdreamlax에 의해 제공되는 정의를 가지고 있습니다.


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.

프리B로SD:

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

소스 저장소는 다음과 같습니다.

@David Titarenco는 여기에 못을 박았지만, 적어도 조금 깨끗하게 하고, 둘 다 보이게 해 주세요.min() 그리고. max()복사와 붙여넣기를 쉽게 할 수 있습니다.:)

2020년 4월 25일 업데이트: C와 C++를 모두 배우거나 C++에서 다른 템플릿으로 전환하는 사람들을 위한 중요한 비교로서 C++ 템플릿을 사용하는 방법을 보여주는 섹션 3도 추가했습니다.저는 이 답변이 몇 번이고 다시 참조할 수 있는 표준 참고가 되도록 철저하고 사실적이며 올바른 답변을 하기 위해 최선을 다했습니다. 여러분도 저처럼 유용하게 사용하길 바랍니다.

1. 기존 C 매크로 방식:

이 기술은 적절하게 사용하는 방법, "사실상의" 작업 방식을 잘 알고 있는 사람들에 의해 잘 알려져 있으며, 적절하게 사용한다면 사용해도 좋지만, 변수 할당을 포함한 표현들을 비교하기 위해 통과시킨 경우(생각: 이중 평가 부작용)가 발생할 수 있습니다.

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

2. 새롭고 개선된 gcc "표현" 방법:

이 기술은 위의 '이중 평가' 부작용과 버그를 회피하기 위해 우수하고 안전하며 보다 현대적인 GCC C 방법으로 간주됩니다.clang은 설계상 gcc 호환성이 있기 때문에 gcc 컴파일러와 clang 컴파일러 모두 사용할 수 있습니다(이 답변 하단의 clang 노트 참조).

, "변수 그림자" 효과는 주의해 주십시오.문장의 표현은 분명히 삽입되어 있기 때문에 자체 로컬 변수 범위가 없습니다.

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

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

gcc 스테이트먼트 식에서 코드 블록의 마지막 식은 함수에서 반환된 것처럼 식에서 반환된 것입니다.GCC의 문서에는 다음과 같이 기재되어 있습니다.

compound 스테이트먼트의 마지막은 식 뒤에 세미콜론을 붙여야 합니다.이 서브프레션의 값은 전체 컨스트럭트의 값으로 기능합니다.(괄호 내에서 다른 종류의 스테이트먼트를 사용할 경우 컨스트럭트의 타입은 void이므로 실질적으로 값이 없습니다.)

3. [C++ 한정] C++ 템플릿 방식:

C++ 주의: C++를 사용하는 경우 이러한 유형의 구성에는 템플릿이 권장될 수 있지만, 개인적으로 템플릿을 싫어하며 C++에서도 C스타일을 자주 사용하고 선호하기 때문에 C++에서 위의 구성 중 하나를 사용할 수도 있습니다.

이 섹션은 2020년 4월 25일에 추가되었습니다.

지난 몇 달 동안 C++를 많이 사용했는데, C++ 커뮤니티에서는 가능하면 매크로보다 템플릿을 더 선호해야 한다는 압박감이 매우 강합니다.그 결과 템플릿을 사용하는 능력이 향상되었습니다.완전성을 위해 여기에 C++ 템플릿 버전을 추가해, 보다 정규적이고 철저한 답변을 하고 싶습니다.

기본 기능 템플릿 버전은 다음과 같습니다.max()그리고.min()C++에서는 다음과 같이 표시됩니다.

template <typename T>
T max(T a, T b)
{
    return a > b ? a : b;
}

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

C++ 템플릿에 대한 자세한 내용은 Wikipedia: 템플릿(C++).

단, 및 는 모두 이미 C++ 표준 라이브러리의 일부입니다.<algorithm>헤더 (#include <algorithm>C++ 표준 라이브러리에서는 위의 것과 약간 다르게 정의되어 있습니다.기본 프로토타입:std::max<>()그리고.std::min<>()예를 들어, C++14에서는 바로 위의 cplusplus.com 링크에서 프로토타입을 살펴봅니다.

template <class T> 
constexpr const T& max(const T& a, const T& b);

template <class T> 
constexpr const T& min(const T& a, const T& b);

이 키워드는typename에일리어스입니다.class(따라서 사용법은 동일합니다.<typename T>또는<class T>C++ 템플릿이 발명된 후 나중에 확인되었으므로 템플릿 타입은 일반 타입일 수 있습니다.int,float클래스 유형뿐만 아니라 , 등).

여기에서는, 입력 타입과 반환 타입이 모두 다음과 같이 되어 있는 것을 알 수 있습니다.const T&이는 "유형에 대한 참조"를 의미합니다.T". 이는 입력 파라미터와 반환값이 값 전달이 아닌 참조로 전달됨을 의미합니다.이는 포인터를 통과하는 것과 비슷하며 클래스 개체와 같은 큰 유형에 더 효율적입니다.constexpr함수의 일부는 함수 자체를 수정하고 함수가 컴파일 시에 평가될 수 있어야 함을 나타낸다(적어도 제공된 경우).constexpr입력 파라미터) 단, 컴파일 시 평가할 수 없는 경우 다른 일반 함수와 마찬가지로 런타임 평가로 기본 돌아갑니다.

constexpr는 C++의 시간 C-매크로와합니다.constexpr시 되며, 는 컴파일 시 수행될 입니다.MIN() ★★★★★★★★★★★★★★★★★」MAX()매크로 대체는 컴파일 시 C 또는 C++에서도 완전히 평가될 수 있습니다.이 C++ 템플릿 정보에 대한 자세한 내용은 아래를 참조하십시오.

4. [C++ ] C++std::max()

C++ 를 사용하고 있는 경우는, 그 기능을 추가해 주세요.<algorithm>헤더 파일에는 다양한 형식이 있습니다.cppreference.com 커뮤니티 Wiki(https://en.cppreference.com/w/cpp/algorithm/max))에 있는 문서 페이지의 "Possible implementation" 섹션을 참조하여 4가지 형식의 구현이 가능합니다.std::max().

통상의 사용법은 다음과 같습니다.

std::max(100, 200);

...하지만 많은 숫자를 한 번에 비교하고 싶다면, 4번째 양식을 사용할 수 있습니다. 4번째 양식을 사용할 수 있습니다.std::initializer_list<T> 이렇게요.

함수 선언:

template< class T, class Compare >
constexpr T max( std::initializer_list<T> ilist, Compare comp );

사용방법:

// Compare **3 or more numbers** by passing a curly-brace-initialized
// `std::initializer_list<>` to `std::max()`!:

std::max({100, 200, 300});                  // result is 300
std::max({100, 200, 300, 400});             // result is 400
std::max({100, 200, 300, 400, 500});        // result is 500
std::max({100, 200, 300, 400, 500, 600});   // result is 600
// etc.

참고 자료:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. C의 MIN과 MAX
  4. 2020년 4월에 추가된 C++ 템플릿 참조:
  5. *****Wikipedia: 템플릿(C++) <-- C++ 템플릿에 대한 훌륭한 추가 정보!
  6. (나만의 질문과 답변):constexpr이 std::max()의 C++14 템플릿 프로토타입의 일부인 이유는 무엇입니까?
  7. constexpr과 const의 차이

Wikipedia의 Clang 노트:

[Clang]은 GNU 컴파일러 컬렉션(GCC)의 드롭인 대체로서 기능하도록 설계되어 대부분의 컴파일 플래그와 비공식 언어 확장을 지원합니다.

관련:

  1. [my answer] 반올림 정수 나눗셈(잘라내기 대신) - 매크로, gcc/clang 문 표현식, C++ 템플릿도 사용합니다.

나는 그들이 표준화된 매크로라고 생각하지 않는다..fmax ★★★★★★★★★★★★★★★★★」fmin (그리고)fmaxf 및 floats로용fmaxl★★★★★★★★★★★★★★★★★★」

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

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

대부분의 경우 컴파일러에 맡기고 원하는 작업을 결정하고 최대한 최적화할 수 있습니다. 하면 , 이렇게 쓰면 가 생기죠.MAX(i++, j++)한 번에 증가하는 값의 최대값을 확인할 필요는 없을 것 같습니다.먼저 증가시킨 다음 확인합니다.

비표준 컴파일러 확장을 피하고 완전 표준 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지원되지 않습니다.이치노

y 중 , 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)둘로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;
}

이것은 꽤 최근의 사태로 인해 늦은 답변입니다.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; })

이 확장의 명백한 이점은 각 매크로 인수가 다음과 같이1회만 확장된다는 것입니다.__typeof__솔루션.

__auto_typeC++11의 제한된 형식입니다.autoC++ 코드에서는 사용할 수 없습니다(또는 사용해서는 안 됩니다).다만, 다음의 뛰어난 타입 추론 기능을 사용하지 않는 것은 타당하지 않습니다.autoC++11을 사용하는 경우.

즉, 이 구문을 사용하는 경우 매크로가 이 구문을 사용하는 데 문제가 없을 으로 생각됩니다.extern "C" { ... }예를 들어 C 헤더로부터의 스코프.AFAIK, 이 내선번호는 해당 경로 정보를 찾을 수 없습니다.

짚고 넘어가야 할 게 있는데, 만약 당신이 이 문제를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)

이전 GCC 확장:연산자<?, >?, <?=, >?=

GCC의 매우 오래된 버전에는 연산자가 있었습니다.<?, >?(여기는 C++로 되어 있었지만, 그 때는 C의 내선번호로도 적용되었다고 생각합니다) 오퍼레이터도 본 적이 있습니다.<?=, >?=할당 스테이트먼트에 대응합니다.

피연산자는 한 번 평가되었으며 매우 짧은 할당 문에 대해서도 허용되었습니다.일반적인 최소/최대 할당에 비해 매우 짧습니다.이것보다 더 나은 것은 없다.

이것들은 다음의 약어였다.

min(a, b)   ===   a < b ? a : b   ===   a <? b;
max(a, b)   ===   a > b ? a : b   ===   a >? b;
a = min(a, b);   ===   if(b < a) a = b;   ===   a <?= b;
a = max(a, b);   ===   if(b > a) a = b;   ===   a >?= b;

최소값을 찾는 것은 매우 간단하다.

int find_min(const int* ints, int num_ints)
{
    assert(num_ints > 0);
    int min = ints[0];
    for(int i = 1; i < num_ints; ++i)
        min <?= ints[i];
    return min;
}

언젠가 GCC로 돌아올 수 있기를 바랍니다. 왜냐하면 이 운영자들은 천재적이기 때문입니다.

처럼 보인다Windef.h(a la.#include <windows.h>)가 있습니다.max그리고.min(소문자) 매크로도 「이중 평가」의 곤란에 시달리고 있습니다만, 독자적인 매크로를 재롤링 하고 싶지 않은 분들을 위해 준비되어 있습니다.

고가의 브랜치를 피하기 위해 min/max가 필요한 경우, 3진 연산자를 사용하지 마십시오.이 연산자는 점프로 컴파일되기 때문입니다.다음 링크에서는 분기하지 않고 최소/최대 함수를 구현하기 위한 유용한 방법을 설명합니다.

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

최대 2개의 정수a그리고.b(int)(0.5((a+b)+abs(a-b)))이것은, 와도 동작할 수 있습니다.(double)그리고.fabs(a-b)복식용(플로트용)

가장 간단한 방법은 글로벌 함수로 정의하는 것입니다..h파일이 많은 모듈러형 프로그램이라면 언제든지 호출할 수 있습니다.아니라면,double MIN(a,b){return (a<b?a:b)}가장 간단한 방법입니다.

그 사람이 "C"라고 한 거 알아요그러나 기회가 있으면 C++ 템플릿을 사용하십시오.

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

safe 라고 입력하고, 다른 코멘트에 기재되어 있는 ++ 에 대해서는 문제가 없습니다.

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

언급URL : https://stackoverflow.com/questions/3437404/min-and-max-in-c

반응형