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::min
와 std::max
C가 있지만 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_type
C ++ 11의 제한된 형식입니다 auto
. C ++ 코드에서는 auto
C ++ 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;
}
나는 그들이 표준화 된 매크로라고 생각하지 않습니다. 표준화 이미 부동 소수점을위한 기능이 있습니다 fmax
과 fmin
(와 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
내가 생각에서 그 가치를 가리키는 것 당신이 정의하는 경우 그 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
(소문자) 매크로는 또한 "이중 평가"어려움으로 고통, 그러나 그렇지 않은 사람들을 위해 거기 있음을 다시 롤 자신 :) 원하는
나는 그 남자가 "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
'development' 카테고리의 다른 글
확장자없이 파일 이름 얻기 (0) | 2020.03.31 |
---|---|
CSS를 사용하여 3 div를 나란히 플로팅하는 방법은 무엇입니까? (0) | 2020.03.31 |
LIKE 와일드 카드를 사용하여 열에서 어떻게 대소 문자를 구분하지 않고 검색 할 수 있습니까? (0) | 2020.03.31 |
프로그래밍 방식으로 LinearLayout에서 여백 설정 (0) | 2020.03.31 |
RStudio를 사용하여 R 업데이트 (0) | 2020.03.31 |