본문 바로가기

Cpp

#define 대신 const, enum, inline 을 생각 할 것

#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