#define, const, enum, inline

·2024년 12월 13일
0

C++

목록 보기
22/26

#define을 쓰려거든 const, enum, inline을 떠올리자

선행 처리자보다 컴파일러를 더 가까이 하자

#define

#define ASPECT_RATIO 1.653

#define을 사용하면 소스 코드가 컴파일러로 넘어가기 전에 선행 처리자가 기호식 이름을 숫자 상수로 변경함 (사용한 만큼 사본 생성)
-> ASPECT_RATIO는 컴파일러가 쓰는 기호 테이블에 들어가지 않기 때문에 디버깅이 어려워짐

const

이런 문제는 상수를 통해 해결할 수 있음

const double AspectRatio = 1.653;

상수를 사용하면 컴파일러의 기호 테이블에 들어감
상수 타입의 ASPECT_RATIO는 아무리 여러 번 쓰여도 사본은 딱 한 개만 생성됨

상수로 교체할 때 두 가지 경우를 조심해야 함
(1) 상수 포인터를 정의하는 경우

  • 상수 정의는 대게 헤더 파일에 넣으므로 포인터와 가리키는 대상을 const로 선언해야 함
// 이 경우에는 char* 기반 문자열보다는 string을 사용하는 것이 좋음
const char* const myName = "Hello";
const std::string myName = "Hello";

(2) 클래스 멤버로 상수를 정의하는 경우

  • 어떤 상수의 유효범위를 클래스로 한정하고자 할 때는 그 상수를 멤버로 만들어야 함
  • 그 상수의 사본 개수가 한 개를 넘지 못하게 하고 싶은 경우엔 정적 멤버로 만들어야 함
// .h 파일
class GamePlayer
{
private:
	static const int NumTurns; // 상수 선언
    int scores[NumTurns];	   // 상수를 사용하는 부분
};

// .cpp 파일
const int GamePlayer::NumTurns = 5; // 상수 정의

enum

정수 상수를 가지고 다른 사람이 주소를 얻는다던지 참조자를 쓴다던지 하는 경우가 싫다면 enum을 사용하는 것이 좋음

class GamePlayer
{
private:
	enum { NumTurns = 5 };
    int score[NumTurns];
};

#define과 매크로 함수

#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))

void f(int maxValue) 
{
    cout << "Max value: " << maxValue << endl;
}

int main()
{
	int a = 5;
    int b = 0;
    CALL_WITH_MAX(++a, b);		// a가 두 번 증가
    CALL_WITH_MAX(++a, b + 10); // a가 한 번 증가
}

f()가 호출되기 전에 a가 증가하는 횟수가 달라짐
이 방법 보다는 템플릿을 사용해서 함수의 동작 방식과 타입 안정성을 모두 취하는 것이 좋음

template<typename T>
inline void callWithMax(const T& a, const T& b)
{
	f(a > b ? a : b);
}

동일한 타입의 객체 두 개를 인자로 받고 둘 중 큰 것을 f에 넘겨서 호출하는 구조임
함수 본문에 괄호를 할 필요도 없고, 인자를 여러 번 평가해도 값이 변할 걱정이 없음

정리

  • 단순한 상수를 쓸 때는 #define 보다 const 객체 혹은 enum을 우선 생각하는 것이 좋음
  • 함수처럼 쓰이는 매크로를 만들고 싶을 때는 #define 매크로보다 인라인 함수를 사용하는 것이 좋음

추가 학습

선언과 정의

  • 선언
    - 변수나 함수가 프로그램에 존재함을 알리지만 메모리 공간을 할당하지 않음
    • 컴파일러에게 이름과 타입을 알려주는 것
  • 정의
    - 변수나 함수에 실제 메모리 공간을 할당하고, 값이나 구현을 제공함
class GamePlayer
{
private:
	static const int NumTurns = 5; // 선언
};

const int GamePlayer::NumTurns;   // 정의

static const int NumTurns = 5;는 선언일까?
클래스 내부에서 정의된 것처럼 보이지만 컴파일러에게 실제 메모리 할당을 알려준 것은 아니기 때문에 선언임

static 멤버 변수, static const 멤버 변수

  • static 멤버 변수
    - 클래스의 인스턴스가 아니라 클래스 자체에 속함
    • 메모리 영역에 저장되며 클래스가 인스턴스화되지 않아도 존재함
  • static const 멤버 변수
    - 상수이므로 컴파일 시점에 그 값을 알 수 있음
    • 컴파일러는 상수 값을 코드에 직접 삽입하거나 변수의 메모리 할당 없이 최적화할 수 있음

클래스 외부에서 정의를 명시해주는 이유

  • 링킹 오류를 방지하기 위해
    - 컴파일러는 해당 변수의 값이 상수라는 것을 인식하지만 외부에서 정의 해주지 않으면 링커가 실제로 그 변수를 참조할 때 해당 변수를 찾을 수 없기 때문
class GamePlayer
{
private:
	static const int NumTurns;
};

int main() 
{
	cout << GamePlayer::NumTurns << '\n';
}

0개의 댓글

관련 채용 정보