typedef 는 기존에 존재하는 자료형의 이름에 새 이름(별명)을 부여하는 것을 목적으로 한다.
예를 들어 앞서 선언한 포인터를 이런식으로 선언한다면,
typedef struct point
{
int xPos;
int yPos;
} Point; /* 구조체 선언과 동시에 struct point에 Point 라는 새 이름(별명)을 부여하게 된다. */
int main(void)
{
Point P; /* struct라는 키워드를 생략하고 구조체 변수를 생성할 수 있다.
Point = struct point 처럼 되었다고 생각하면 된다.
P.xPos = 3;
P.yPos = 5;
}
보통 데이터를 묶어 사용할 때 struct를 많이 사용하는데 struct와 typedef struct의 차이점을 모르고 사용하는 경우가 있습니다. 이에 그 차이점을 정리해 보고자 합니다.
struct의 사용법으로 3가지 정도가 있습니다
아래와 같습니다.
1>
typedef struct
{
int data;
int text;
} S1;
// S1이라고 타입정의합니다. C와 C++에서 문제없이 동작합니다.
2>
struct S2
{
int data;
int text;
};
//S2라고 타입정의합니다. 이 형태는 C++에서만 가능합니다. C에서는 Error를 냅니다.
3>
struct
{
int data;
int text;
}S3;
// 이 문장은 C와 C++에서 문제없이 동작합니다.
// 하지만 주의할 점은, S3를 타입정의가 아닌 직접 변수로 선언하게 됩니다. S3자체가 변수입니다.
// 컴파일러는 S3변수를 위한 메모리를 할당하게 됩니다. S1,S2는 타입정의만 하기 때문에 메모리 할당이 당연히 없습니다.
// 사용 예
void main()
{
S1 mine1; // 문제없이 동작합니다. 이때 S1은 typedef입니다.
S2 mine2; // 역시 문제없이 동작합니다. 이때 S2도 역시 typedef입니다.
S3 mine3; // 문제가 발생합니다! S3는 typedef가 아니라 변수입니다. 따라서 S3 mine3;는 옳지 않습니다.
S1.data = 5; // 에러가 발생합니다. S1은 변수가 아닌 typedef입니다.
S2.data = 5; // 역시 에러가 발생합니다. S2는 변수가 아닌 typedef입니다.
S3.data = 5; // 잘 동작합니다. S3자체가 변수이기 때문에 문제가 없습니다.
}
다음으로 linked lists를 사용할 때 차이점을 알아보겠습니다.
1>
struct S6
{
S6* ptr;
};
// 위 문장은 C++에서만 가능합니다. C++ only
// C++에서는 위와같이 linked lists구조로 갈 수 있겠죠.
2>
typedef struct
{
S7* ptr;
}S7;
// 위 문장은 언뜻보면 문제가 없을 것으로 보이지만, 일단 C나 C++에서 에러를 낸다고 합니다.
// 하지만 무조건 에러를 내는것은 아닙니다. 컴파일러가 single-pass 이냐 multi-pass이냐에 따라서 가불이 결정됩니다.
gcc컴파일러 같은 single-pass의 경우 방금 말한 것처럼 저런 구문은 안됩니다. 이유는, S7* ptr; 구문에서 S7의 형태를 미처 파악 못하였기 때문에 에러를 내고 사용할 수 없다고 합니다. 하지만 multi-pass컴파일러의 경우는, 일단 저 문제시되는 부분에서는 에러 대신 unresolved symbol로 해놓고 지나갑니다. 그 후 다시 그 부분을 재처리해서 문제없이 동작하게끔 합니다. 컴파일러의 차이에 의해서 저 구문이 가능할 수도 있고 불가능할 수도 있다는 게 요지입니다.
대안책으론, S7* ptr; 대신 void* ptr;로 대체하고 타입캐스팅을 이용하면 문제없이 저 형태를 쓸 수 있을 것입니다. 그리고 struct대신에 class를 사용해도 문제 해결이 될 것입니다.
이상 간략하게 struct{}와 typedef struct{}에 대하여 알아봤습니다.