Constexpr 대 매크로
매크로 사용을 선호하는 곳과 constexpr을 선호하는 곳은 어디 입니까? 기본적으로 동일하지 않습니까?
#define MAX_HEIGHT 720
vs
constexpr unsigned int max_height = 720;
기본적으로 동일하지 않습니까?
아뇨. 절대 아닙니다. 근처에도 안.
그렇다 사실에서 매크로는이다 int
당신은 constexpr unsigned
입니다 unsigned
만이 중요한 차이점 및 매크로가, 하나의 장점은.
범위
매크로는 전처리기에 의해 정의되며 발생할 때마다 코드로 대체됩니다. 전처리 기는 멍청 하고 C ++ 구문이나 의미를 이해하지 못합니다. 매크로는 네임 스페이스, 클래스 또는 함수 블록과 같은 범위를 무시하므로 소스 파일에서 다른 이름을 사용할 수 없습니다. 적절한 C ++ 변수로 정의 된 상수에는 해당되지 않습니다.
#define MAX_HEIGHT 720
constexpr int max_height = 720;
class Window {
// ...
int max_height;
};
max_height
클래스 멤버이므로 범위가 다르고 네임 스페이스 범위의 변수 와 구별되기 때문에 멤버 변수를 호출 하는 것이 좋습니다. MAX_HEIGHT
멤버 의 이름을 재사용하려고 하면 전처리 기가 컴파일하지 않는 말도 안되는 이름 으로 변경합니다.
class Window {
// ...
int 720;
};
이것이 UGLY_SHOUTY_NAMES
눈에 띄는 매크로를 제공해야하는 이유 이며 충돌을 피하기 위해 이름을 지정할 때주의 할 수 있습니다. 매크로를 불필요하게 사용하지 않는다면 그것에 대해 걱정할 필요가 없습니다 (그리고 읽을 필요도 없습니다 SHOUTY_NAMES
).
함수 내부에 상수를 원하면 전처리 기가 함수가 무엇인지 또는 그 안에 있다는 의미를 알지 못하기 때문에 매크로로이를 수행 할 수 없습니다. 매크로를 파일의 특정 부분으로 만 제한하려면 #undef
다시 필요 합니다.
int limit(int height) {
#define MAX_HEIGHT 720
return std::max(height, MAX_HEIGHT);
#undef MAX_HEIGHT
}
훨씬 더 현명한 것과 비교하십시오.
int limit(int height) {
constexpr int max_height = 720;
return std::max(height, max_height);
}
왜 매크로를 선호합니까?
실제 메모리 위치
constexpr 변수 는 변수 이므로 실제로 프로그램에 존재하며 주소를 가져오고 참조를 바인딩하는 것과 같은 일반적인 C ++ 작업을 수행 할 수 있습니다.
이 코드에는 정의되지 않은 동작이 있습니다.
#define MAX_HEIGHT 720
int limit(int height) {
const int& h = std::max(height, MAX_HEIGHT);
// ...
return h;
}
문제는 MAX_HEIGHT
변수가 아니기 때문에 std::max
임시 호출을 int
컴파일러에 의해 생성해야한다는 것입니다. 에서 반환되는 std::max
참조는 해당 문이 끝난 후에 존재하지 않는 임시를 참조 할 수 있으므로 return h
잘못된 메모리에 액세스합니다.
이 문제는 적절한 변수가 있으면 존재하지 않습니다. 왜냐하면 메모리에서 사라지지 않는 고정 된 위치를 가지고 있기 때문입니다.
int limit(int height) {
constexpr int max_height = 720;
const int& h = std::max(height, max_height);
// ...
return h;
}
(In practice you'd probably declare int h
not const int& h
but the problem can arise in more subtle contexts.)
Preprocessor conditions
The only time to prefer a macro is when you need its value to be understood by the preprocessor, for use in #if
conditions, e.g.
#define MAX_HEIGHT 720
#if MAX_HEIGHT < 256
using height_type = unsigned char;
#else
using height_type = unsigned int;
#endif
You couldn't use a variable here, because the preprocessor doesn't understand how to refer to variables by name. It only understands basic very basic things like macro expansion and directives beginning with #
(like #include
and #define
and #if
).
If you want a constant that can be understood by the preprocessor then you should use the preprocessor to define it. If you want a constant for normal C++ code, use normal C++ code.
The example above is just to demonstrate a preprocessor condition, but even that code could avoid using the preprocessor:
using height_type = std::conditional_t<max_height < 256, unsigned char, unsigned int>;
Generally speaking, you should use constexpr
whenever you may, and macros only if no other solution is possible.
Rationale:
Macros are a simple replacement in the code, and for this reason, they often generate conflicts (e.g. windows.h max
macro vs std::max
). Additionally, a macro which works may easily be used in a different way which can then trigger strange compilation errors. (e.g. Q_PROPERTY
used on structure members)
Due to all those uncertainties, it is good code style to avoid macros, exactly like you'd usually avoid gotos.
constexpr
is semantically defined, and thus typically generates far less issues.
Great answer by Jonathon Wakely. I'd also advise you to take a look at jogojapan's answer as to what the difference is between const
and constexpr
before you even go about considering the usage of macros.
Macros are dumb, but in a good way. Ostensibly nowadays they're a build-aid for when you want very specific parts of your code to only be compiled in the presence of certain build parameters getting "defined". Usually, all that means is taking your macro name, or better yet, let's call it a Trigger
, and adding things like, /D:Trigger
, -DTrigger
, etc. to the build tools being used.
While there's many different uses for macros, these are the two I see most often that aren't bad/out-dated practices:
- Hardware and Platform-specific code sections
- Increased verbosity builds
So while you can in the OP's case accomplish the same goal of defining an int with constexpr
or a MACRO
, it's unlikely the two will have overlap when using modern conventions. Here's some common macro-usage that hasn't been phased out, yet.
#if defined VERBOSE || defined DEBUG || defined MSG_ALL
// Verbose message-handling code here
#endif
As another example for macro-usage, let's say you have some upcoming hardware to release, or maybe a specific generation of it that has some tricky workarounds that the others don't require. We'll define this macro as GEN_3_HW
.
#if defined GEN_3_HW && defined _WIN64
// Windows-only special handling for 64-bit upcoming hardware
#elif defined GEN_3_HW && defined __APPLE__
// Special handling for macs on the new hardware
#elif !defined _WIN32 && !defined __linux__ && !defined __APPLE__ && !defined __ANDROID__ && !defined __unix__ && !defined __arm__
// Greetings, Outlander! ;)
#else
// Generic handling
#endif
ReferenceURL : https://stackoverflow.com/questions/42388077/constexpr-vs-macros
'IT박스' 카테고리의 다른 글
동적 매개 변수로 ui-router 해석 (0) | 2021.01.11 |
---|---|
MySQL Sum () 여러 열 (0) | 2021.01.11 |
Angular 2 : 배열의 변화를 감지하는 방법은 무엇입니까? (0) | 2021.01.11 |
Constraint Layout에서 Barrier와 Guideline의 차이점은 무엇입니까? (0) | 2021.01.11 |
Visual Studio Community 2015 내에서 Android 용 Xamarin을 업데이트하는 방법 (0) | 2021.01.10 |