[C][Macro] min max
γλͺ©μ°¨γ
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()
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