λ£¨λ°€π•ƒπ•¦π•„π•šπ•£ 2023. 2. 21. 23:49
728x90
λ°˜μ‘ν˜•
γ€Žλͺ©μ°¨γ€
1. The old C macro way

2. The new improved gccㆍclang "statement expression" way
3. [C++] std::min() & std::max()
4. 좜처

1. The old C macro way

맀크둜 μ›ν˜•
/* min */
#define min(a, b) (((a) < (b)) ? (a) : (b))

/* max */
#define max(a, b) (((a) > (b)) ? (a) : (b))
단점 : double-evaluation side effect λ°œμƒ
/* Input */
#include <stdio.h>
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))

int main(int argc, char * argv[]) {
	int a = 2, b = 3;

	printf("%d\n", min(a, b));
	printf("a : %d b : %d\n\n", a, b);

	printf("%d\n", max(a, b));
	printf("a : %d b : %d\n\n", a, b);

	printf("%d\n", min(a++, b++)); // a++은 2번, b++은 1번 κ³„μ‚°λ˜μ–΄, a=4 b=4 κ°€ λœλ‹€.
	printf("a : %d b : %d\n\n", a, b);

	printf("%d\n", max(a--, b--)); // a--λŠ” 1번, b--λŠ” 2번 κ³„μ‚°λ˜μ–΄, a=3 b=2 이 λœλ‹€.
	printf("a : %d b : %d\n\n", a, b);

	return 0;
}
/* Output */
2
a : 2 b : 3

3
a : 2 b : 3

3
a : 4 b : 4

3
a : 3 b : 2

min(a++, b++) ν˜Ήμ€ max(a++, b++) λ“± 맀크둜 λ‚΄λΆ€μ—μ„œμ˜ μ „μœ„γ†ν›„μœ„ 증감 μ—°μ‚° μ‹œ, a λ˜λŠ” b값을 1μ”©λ§Œ μ¦κ°€μ‹œν‚€λ €λŠ” μ˜λ„μ™€λŠ” λ‹€λ₯΄κ²Œ, a λ˜λŠ” b의 값이 2λ²ˆμ”© μ¦κ°λ˜λŠ” κ²½μš°κ°€ λ°œμƒν•œλ‹€.

원문

This technique is commonly used, well-respected by those who know how to use it properly, the "de facto" way of doing things, and fine to use if used properly, but buggy (think: double-evaluation side effect) if you ever pass expressions including variable assignment in to compare:

2. The new improved gccㆍclang "statement expression" way

맀크둜 μ›ν˜•
/* __typeof__κ°€ μ •μ˜λ˜μ–΄ μžˆλŠ” GCC 및 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;       \
})

Using __typeof__ ensures the arguments are evaluated only once, which avoids eg. function call overhead. It's a GCC-specific C extension, C++ gives you function templates as part of the language.

__typeof__ λŒ€μ‹  typeofλ₯Ό μ΄μš©ν•  경우
#define max(a,b)	  \
({			  \
    typeof (a) _a = (a);  \
    typeof (b) _b = (b);  \
    _a > _b ? _a : _b;    \
})

typeofλŠ” μ’…μ’… λ¬Έ ν‘œν˜„μ‹κ³Ό ν•¨κ»˜ μœ μš©ν•©λ‹ˆλ‹€( Statement Expr μ°Έμ‘° ). λ‹€μŒμ€ 두 가지λ₯Ό ν•¨κ»˜ μ‚¬μš©ν•˜μ—¬ λͺ¨λ“  μ‚°μˆ  μœ ν˜•μ—μ„œ μž‘λ™ν•˜κ³  각 인수λ₯Ό μ •ν™•νžˆ ν•œ 번만 ν‰κ°€ν•˜λŠ” μ•ˆμ „ν•œ "μ΅œλŒ€" 맀크둜λ₯Ό μ •μ˜ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.

지역 λ³€μˆ˜μ— λ°‘μ€„λ‘œ μ‹œμž‘ν•˜λŠ” 이름을 μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” a 와 b 둜 λŒ€μ²΄λ˜λŠ” ν‘œν˜„μ‹μ—μ„œ λ°œμƒν•˜λŠ” λ³€μˆ˜ μ΄λ¦„κ³Όμ˜ μΆ©λŒμ„ ν”Όν•˜κΈ° μœ„ν•΄μ„œ μž…λ‹ˆλ‹€. κ²°κ΅­, μš°λ¦¬λŠ” λ²”μœ„κ°€ μ΄ˆκΈ°ν™” μ΄ν›„μ—λ§Œ μ‹œμž‘λ˜λŠ” λ³€μˆ˜λ₯Ό μ„ μ–Έ ν•  μˆ˜μžˆλŠ” μƒˆλ‘œμš΄ ν˜•νƒœμ˜ μ„ μ–Έ ꡬ문을 μ„€κ³„ν•˜λ €κ³  ν•©λ‹ˆλ‹€. μ΄λŠ” μ΄λŸ¬ν•œ μΆ©λŒμ„ λ°©μ§€ν•˜λŠ”, 보닀 μ•ˆμ •μ μΈ λ°©λ²•μž…λ‹ˆλ‹€.

GCC(GNU 컴파일러)μ—μ„œμ˜ __typeof__ 예제 (GCC = GNU Compiler Collection)
#include <stdio.h>

#define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
        
#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;       \
})

int main(int argc, char* argv[]) {
	int a = 5;
	int b = 3;

	printf("Smaller value (not safe): %d\n", MIN(a, b));
	printf("a: %d, b: %d\n", a, b);

	printf("Smaller after ++ (safe): %d\n", min(a++, ++b));
	printf("a: %d, b: %d\n", a, b);

	printf("Smaller after ++ (not safe): %d\n", MIN(a++, b++));
	printf("a: %d, b: %d\n", a, b);

	int c = 7;
	int d = 8;
	printf("Larger value: %d\n", max(c, d));

	return 0;
}
원문

This technique avoids the above "double-evaluation" side effects and bugs, and is therefore considered the superior, safer, and "more modern" GCC C way to do this. Expect it to work with both the gcc and clang compilers, since clang is, by design, gcc-compatible (see the clang note at the bottom of this answer).

BUT: DO watch out for "variable shadowing" effects still, as statement expressions are apparently inlined and therefore do NOT have their own local variable scope!

Note that in gcc statement expressions, the last expression in the code block is what is "returned" from the expression, as though it was returned from a function. GCC's documentation says it this way:

The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)

3. [C++ ]  std::min() & std::max() 

https://lumir.tistory.com/49

 

[C++][header][algorithm] min max

γ€Žλͺ©μ°¨γ€ 0. μ„€λͺ…에 μ•žμ„œ 1. Default Constructor 2. Custom Constructor 3. Initializer List Constructor 0. std::min & std::max γ€Žμ„€λͺ…에 μ•žμ„œγ€ μ°Έκ³  1. ①비ꡐ할 값듀이 λ§Žκ±°λ‚˜, β‘‘ArrayㆍVector와 같은 일련의 μ»¨ν…Œμ΄λ„ˆμ—

lumir.tistory.com

c++μ—μ„œμ˜ min max ν•¨μˆ˜μ˜ ν™œμš©μ€ μœ„ 링크λ₯Ό μ°Έκ³ ν•˜μž.

4. 좜처

https://betterembsw.blogspot.com/2017/07/dont-use-macros-for-min-and-max.html

https://stackoverflow.com/questions/3437404/min-and-max-in-c/3437442#3437442

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

728x90
λ°˜μ‘ν˜•