#define 매크로를 사용하면 선행 처리되면서 기호 테이블에 들어가지 않으며 컴파일러에게도 보이지 않는다.
그래서 디버깅 시에 찾기 어려울 수도 있다 매크로 이름이 아닌 값으로 에러 메시지가 나올 것 이기 때문에 확실히 파악하기 어려울 수 있다.
매크로 대신 상수를 쓸 수 있다.
const double Aa = 1.653;
const 이기 때문에 컴파일러의 눈에 보이고 기호 테이블에도 들어간다.
매크로 사용시 코드에 매크로 이름이 나타나면 선행 처리로 값으로 바뀌면서 목적 코드 안에 값 등장 횟수만큼 사본이 들어간다. 다만, 상수 타입 사용시에는 사본이 딱 한 번 생성된다.
#define 대신 상수를 사용한다면 조심해야 할 것
1. 상수 포인터를 사용할 경우 : 상수 포인터를 쓴다면 안정적으로 const 를 양쪽에 배치하여 값, 주소 변경이 되지 않도록 한다.
const int* const aa = 4;
2. 클래스 멤버를 상수로 정의할 경우 : 클래스 상수를 만든다면 상수 사용시 마다 사본 개수가 늘어나지 않도록 static 을 사용할 수 있다.
class PP{
static const int NumTurns = 5;
};
다만 static 으로 선언되었다면 cpp 에서 정의해준다.
// cpp
const int PP::NumTurns; //정의
이때 값을 대입하지 않는다. 이미 선언시 초기화 했기 때문이다.
나열자 둔갑술
enum 은 메모리 할당 없이 정수 상수를 정의 할 수 있는 특징이 있다. 이것은 #define 과 유사하게 작동 할 수 있다는 의미이다. 그에 더 해 타입 안정성을 제공할 수 도 있다.
다만 이 나열자 둔갑술을 왜 사용하냐. 구식 컴파일러가 static const 로 이루어진 클래스 상수를 배열 크기로 받아들이지 못할 수 있기 때문이다. 따라서 아래와 같이
class GamePlayer {
private:
enum { NUM_PLAYERS = 5 }; // 정적 상수 대신 enum 사용
int scores[NUM_PLAYERS]; // 배열 크기로 사용 가능
public:
void printScores() {
for (int i = 0; i < NUM_PLAYERS; ++i) {
scores[i] = i * 10; // 예제 값 할당
std::cout << "Player " << i << " Score: " << scores[i] << "\n";
}
}
};
int main() {
GamePlayer player;
player.printScores();
return 0;
}
사용하면 구식 컴파일러에서도 오류 나지 않고 사용 가능하다. 이러한 나열자 둔갑술은 템플릿 메타프로그래밍의 핵심 기법이다.
#define 을 이용한 식을 만드는 것 대신 inline 사용
매크로 이용해 식을 만들면 항상 (,) 에 굉장히 조심해야한다. 또한, 삼항 연산자와 같은 계산식 사용시 매크로를 활용하면
더 복잡한 문제가 야기 되기도 한다.
따라서 템플릿 inline 을 대체하여 사용할 수 있따.
// 템플릿 인라인 함수 정의
template<typename T>
inline void callWithMax(const T& a, const T& b) {
f(a > b ? a : b);
}
다음과 같이 사용하면 () 를 많이 사용하지 않는다. 계산식에 오류가 나올일도 없으며 진짜 함수의 일종이기 때문에 유효범위와 접근 규칙을 가지고 있다.
'Cpp' 카테고리의 다른 글
객체 사용 전 객체 초기화 (1) | 2024.12.15 |
---|---|
const 사용 (1) | 2024.12.15 |
C++의 하위 언어 (0) | 2024.12.14 |
바이트 패딩 (0) | 2024.11.18 |
RAII란? (0) | 2024.11.02 |