typedef 이해하기
typedef BOOL int;
typedef int BOOL;
둘 중 어느 것이 맞는지 단박에 알아차릴 수 있겠는가?
나는 typedef만 쓰려고 하면 지금도 둘 중에 뭐가 맞는지 헷갈리고는 한다.
답은 아래 것이 맞다.
그럼 앞에 있는 타입으로부터 뒤에 따라오는 새로운 타입을 만들겠다는 말인가?
아래 정의들을 보자.
typedef int BOOL, *PBOOL;
typedef struct tagFILEINFO
{
int i;
} FILEINFO, *PFILEINFO;
이제 또 어디부터가 앞이고 뒤인지 헷갈린다.
typedef BOOL (*fn_t)(int, int*);
함수의 경우에는 조금 더 머리가 아프다.
빌어먹을, 대체 어디가 앞이고 어디부터 뒤란 말인가?
typedef
을 정의할 때는 이를 헷갈리지 않기 위해서 딱 한 가지만 기억하면 된다.
변수를 적어야 할 위치에 새로운 타입을 적어라.
위에 나왔던 typedef
들을 하나씩 살펴보겠다.
빨간색은 타입이요, 파란색은 변수이다.
int형 변수를 선언할 때는 다음처럼 한다.
int
i
;
아래처럼 한 줄에 포인터 변수와 같이 선언할 수도 있다.
int
j, *p
;
이제 typedef
를 다시 보면
// 변수를 적어야 할 위치에 새로운 타입을 적는다.
typedef int BOOL;
typedef int BOOL, *PBOOL;
구조체를 정의함과 동시에 변수를 만들 수 있다는 것도 알고 있을 것이다.
struct FILEINFO { int i; }
fileInfo
; // 구조체를 선언함과 동시에 전역 공간에 fileInfo 라는 인스턴스를 생성하였다.
물론 아래처럼 여러 변수를 만들 수도 있다.
struct FILEINFO { int i; }
fileInfo, *pFileInfo, ***pppFileInfo
;
이제 typedef
를 다시 보면
// 변수를 적어야 할 위치에 새로운 타입을 적는다.
typedef struct tagFILEINFO
{
int i;
} FILEINFO, *PFILEINFO, ***PPPFILEINFO;
아래 함수를 나타내는 타입은 무엇일까?
BOOL foo(int i, int* p);
foo
는 함수 이름이고 타입은 다음과 같다.
BOOL (*)(int, int*)
타입이 있으므로 변수도 만들 수 있다.
그런데 함수의 경우에는 변수가 뒤쪽에 붙는 것이 아니라 가운데에 들어가는 것을 이해하는 것이 중요하다.
BOOL(*)(int, int*)
이라는 타입의 변수 pfn
을 선언하려면 다음과 같이 한다.
BOOL (*
pfn
)(int, int*);
함수 포인터를 사용하는 예제도 한 번 살펴보고 넘어가자.
void foo(int x)
{
printf("%d", x);
}
int main()
{
// void (*)(int) 타입의 변수 pfn을 정의하면서 동시에 foo를 대입한다.
void (*pfn)(int) = foo;
pfn(10); // 함수 포인터로 함수 호출도 가능하다.
}
이제 typedef
를 다시 보면,
// 변수를 적어야 할 위치에 새로운 타입을 적어라.
typedef BOOL (*fn_t)(int, int*); // fn_t라는 새로운 타입을 정의하였다.
함수에 호출 규약까지 넣는 경우에는 아래처럼 꼭 괄호 안에 호출 규약을 넣어 주어야 한다.
typedef BOOL (__stdcall *fn_t)(int, int*);
멤버 함수의 경우에는 타입을 다음처럼 쓴다.
void (MyClass::*)(int, int*);
위에서 설명한 규칙을 잘 기억했다면 이제 typedef을 쉽게 만들어 낼 수 있다.
// 변수를 적어야 할 위치에 새로운 타입을 적어라.
typedef void (MyClass::* memberfn_t)(int, int*);
함께 읽으면 좋은 글: