시작은 미미하나 끝은 쥬쥬하리라.

Develop/Language - C++

[C++] typedef

코딩뚜벅이 2026. 1. 22. 17:22
반응형

목차

1. typedef

2. 응용/심화

3. 요약

 


1. typedef

typedef : 타입에 별칭을 만드는 도구

// C++98
typedef int (*PFN_Compute)(int a, int b);

int Add(int a, int b) { return a + b; }
PFN_Compute fn = &Add;

 

-> fn(1,2)를 하게되면 Add(1,2)가 호출되며 3의 리턴값을 반환.

 

- typedef는 기존의 선언 문법을 그대로 따라가기 때문에 포인터 혹은 중첩 타입에서의 가독성이 급격하게 떨어짐.

-> 별칭(Alias)가 중간에 끼어들어 한 눈에 들어오지 않음.

 


2. 응용/심화

typedef vs using

typedef는 기존의 선언 문법을 그대로 따라가지만 using은 대입 연산자 형식을 사용.ex) ty[edef int (*PFN_HANDLER)(int, int); <-> using HandlerPtr = int(*)(int, int);-> 새로운 이름이 무엇인지 명확함.

 

// C++11+
using PFN_Compute = int (*)(int, int);

using Byte = unsigned char;
using Size = std::size_t;

 

- typedef는 템플릿 자체를 별칭으로 만들 수 없어 특정 타입으로 고정하거나 구조체 내부에 넣어 우회해야함.- using은 템플릿 인자를 그대로 유지하면서 별칭 생성 가능.

 

ex) 예시 : typedef

template <typename T>
struct SensorMap {
    // 템플릿 별칭이 안 되어 구조체로 감싸야 함
    typedef std::map<int, T> type;
};

SensorMap<float>::type myMap; // 사용 시 매번 ::type을 붙여야 함

 

 

ex) 예시 : using

template <typename T>
using SensorMap = std::map<int, T>; // 직관적인 템플릿 별칭

SensorMap<float> myMap; // 간결하고 명확함

 

ex) 선언 방식 비교

구분 typedef 방식 (과거) using 방식 (현대)
기본 타입 typedef int INT32; using INT32 = int;
배열 typedef int ARR[10]; using ARR = int[10];
함수 포인터 typedef void (*PFN)(int); using PFN = void (*)(int);

 

 

타입 트레잇(Type Traits) 기반 설계와 typedef

컴파일 시간에 타입을 검사하고 변환하는 기법, 최근 C++ 설계 트렌드에서 선호.

-> typedef를 사용하는 경우 std::와 같은 메타 함수를 사용할 때, 매번 typename 키워드와 ::type을 붙여야하는 의존적 타입 문제에 직면.

 

ex) 예시 : typedef

template <typename T>
struct SensorMap {
    // 템플릿 별칭이 안 되어 구조체로 감싸야 함
    typedef std::map<int, T> type;
};

SensorMap<float>::type myMap; // 사용 시 매번 ::type을 붙여야 함

 

 

ex) 예시 : using

template <typename T>
using MyList = std::list<T>; // 별명 자체가 템플릿!

// 사용할 때 (매우 직관적)
MyList<int> m_list; 

// 다른 템플릿 안에서 쓸 때도
template <typename T>
void Process() {
    MyList<T> data; // 'typename' 필요 없음!
}

 

 

실무 가독성

현장에서는 Millisecond, ErrorCode와 같은 의미를 담은 타입을 정의하는 것이 중요.

-> 단순 int를 사용하는 것이 아닌 using TickCount = unsigned long;과 같은 의미를 부여.

// [의미 부여 전]
unsigned long start = GetTickCount();
int result = Connect();

// [의미 부여 후: using 활용]
using TickCount = unsigned long;  // 시간 단위(ms)임을 명시
using ErrorCode = int;            // 반환값이 단순 숫자가 아닌 에러코드임을 명시

TickCount startTime = GetTickCount();
ErrorCode connectionResult = Connect();

if (connectionResult == 0) { /* 성공 처리 */ }

 

 

CallBack 시크니처가 변경되는 경우 별칭 하나만 수정하면 프로젝트 전반에 안전하게 반영될 수 있도록.

// 1. 먼저 콜백의 형식을 별칭으로 정의합니다.
// (나중에 인자가 추가되어도 여기만 수정하면 됩니다.)
using OnReceiveCallback = void (*)(int deviceId, const char* data);

// 2. 실제 함수들
void MyDisplayLog(int id, const char* msg) { /* 로그 출력 */ }

// 3. 라이브러리 등록 함수
void RegisterCallback(OnReceiveCallback cb) { /* ... */ }

// [적용]
RegisterCallback(MyDisplayLog);

 

 

구 버전의 C++인 경우 typedef를 사용하되 주석을 통해 타입의 의도를 명확히 하고 가급적 함수 포인터 등은 단순화해서 정의.

/* * [구 버전 방식]
 * 의미: 장치로부터 넘어오는 원시 데이터 처리 콜백
 * PFN: Pointer to FuNction의 약어
 */

// 복잡한 함수 포인터를 한 번에 쓰지 말고 주석과 함께 정의
// void (*)(int, double) 형태
typedef void (*PFN_DeviceHandler)(int unitId, double value);

/* 시스템 전역에서 공유하는 핸들 타입 */
typedef unsigned int SYSTEM_HANDLE;

// 함수 정의 시 사용
void ProcessData(PFN_DeviceHandler handler, SYSTEM_HANDLE hSys) {
    // 로직 구현
}

 


3. 요약

typedef : 타입에 별칭을 만드는 도구이지만 가독성이 떨어짐.

using : 타입 트레잇 기반 설계라는 최신 트렌드와 맞물려 typedef 대신 최신 C++에서 선호, 템플릿 별칭도 가능.

반응형