본문 바로가기
Programming/C & C++

struct 와 typedef struct 의 차이점

by leanu 2008. 1. 2.

struct _tagPoint{
     int x;
     int y;
};

POINTS는 선언되지 않은 심볼이므로 struct _tagPoint POINTS;라고 하면,

POINTS라는 이름의 구조체 변수가 생성됩니다.

당연히 POINTS는 타입으로 선언된 것이 아니므로 POINTS s;라는 구문은 오류입니다.

struct의 임무는 뒤에 나오는 식별자 _tagPoint가

구조체 태그이름임을 나타내는 지시어입니다.

이는 C와의 하위 호환성을 위해 남겨둔 것으로,

C++에서는 선택적으로 사용해도 되고, 사용하지 않아도 상관 없습니다.

C에서 변수선언은 기본적으로

"변수 선언이 가능한 키워드로 시작"될 때만

변수 선언으로 인식하도록 되어 있는 구조입니다.

따라서 한 문장의 시작이 int, char, void 등의 타입을 나타내는

'키워드'여야만 유효한 선언으로 간주하는 구조로 설계되었습니다.

enum이나 union, struct등의 사용자 정의 타입은

그냥 선언한 이름만 쓰면 변수 선언으로 인식하지 못하는 구조이죠.

그래서 해당 타입이 무엇으로 선언되어 있는지를

컴파일러에게 알려주도록 C언어는 설계되었습니다.


 

하지만 C의 슈퍼셋으로 설계된 C++은

사용자 정의 타입 역시 기본 데이터 타입과 통합된 타입 시스템으로 관리하므로,

더이상 사용자 정의 타입의 변수를 생성할 때 그 종류를 알려줄 필요가 없지만,

C와의 하위 호환성을 위해 남겨둔 것 뿐입니다.

C에서 사용자 정의 데이터 타입의 변수를 선언하려면

사용자 정의 타입임을 나타내는 키워드(enum, struct, union 등)와

선언된 타입의 태그 이름을 같이 적어 주어야 했습니다.

하지만 매번 struct를 써주는 것도 번거로운 일이므로,

C에서는 사용자 정의 타입 이름도 typedef 로 재정의 가능하도록 허용했습니다.

그래서 C에서는 사용상의 편의를 위해서 구조체 선언과 동시에

구조체의 태그 이름으로 별 의미없는, 잘 안쓰는 이름을 붙이고

typedef 이름을 잘 쓰이고 읽기 쉬운 이름으로 붙이는 관습이 생겨난 것입니다.

C에서

struct POINTS
{
    int x, y;
};

POINTS s;

라고 변수를 정의하면, 컴파일 에러를 냅니다.

이는 POINTS가 타입이름으로 선언된 이름이 아니라,

사용자 정의 타입의 태그 이름으로만 선언된 이름

이기 때문이죠.

태그이름과 타입이름은 엄연히 다른 것이니까요.

하지만 C++ 에서 위의 코드는 아무런 문제가 없습니다.

C++의 타입 시스템은 사용자정의 타입도 기본 데이터 타입과 마찬가지로 취급하므로

구조체 태그 이름을 선언하는 순간, 그 이름이 타입 시스템 내에서

유효한 타입이름으로 등록되어 사용할 수 있게 되므로, C++에서는 사실상

typedef로 타입을 선언하나, 그냥 struct만으로 선언하나 아무런 차이가 없습니다.

단, 여기서 주의할 점은, 다음과 같은 구문에서,

typedef struct
{
    int x, y;
} POINTS;

이와 같은 구문은 컴파일러는 이렇게 해석합니다.

a. 이름없는 구조체를 만들고,

b. 여기에 두 멤버변수 x,y를 추가하고

c. 이 이름없는 구조체의 타입이름을 POINTS로 재정의한다.

여기서 문제가 되는 것은 '이름없는 구조체'를 만드는 것이

컴파일러에 따라 지원될 수도 있고, 안될 수도 있다는 것이죠.

'이름없는 구조체'는 언어 표준에서 명시된 것이 아니므로,

이를 지원하는 컴파일러는 살짝 표준에서 빗겨나가 있긴 하지만

대부분의 컴파일러가 지원하는 기능이므로 대부분 저렇게 쓰기도 합니다.

하지만, 진짜 언어 표준만을 지원하는 컴파일러는

위와 같은 구문은 컴파일시 에러나 워닝을 냅니다.

그래서 그와 같은 컴파일러에서는 구조체를 typedef로 새 타입이름으로 선언하더라도,

임시로 사용할 태그 이름이 필요하게 됩니다.

따라서, 이와 같은 컴파일러에서는 다음과 같이 임시 태그 이름을 사용하여

typedef로 타입 이름을 선언해야 합니다.

(물론, 번거롭긴 하지만 표준과 일치하는 방법입니다.)

typedef struct _tagPoint{
     int x;
     int y;
}POINT;

이와 같은 구문은,

어떤 컴파일러를 쓰더라도 정확히 동일한 결과를 내므로

안전한 기법이라고 할 수 있겠습니다.

POINTS라는 이름이 끝에 온다면,

이는 typedef 타입 이름으로 간주되 POINTS라는 이름이 struct 뒤에 바로 온다면

구조체 태그 이름으로 간주된다는 차이가 있습니다.

즉, 첫번째 예제의 POINTS는 typedef 타입 이름이 되며,

두번째 예제의 POINTS는 구조체 태그 이름이 됩니다.

반면, 세번째 예제에서는 typedef구문인데,  POINTS는 구조체 태그 이름만 있고

typedef로 선언할 새 타입 이름이 없으므로 오류입니다.

typedef의 기본 구문은,

typedef (기존타입) (새타입이름);

과 같은 형식입니다.

typedef struct POINT{
     int x;
     int y;
};

와 같이 쓴다면, struct POINT { ... } 이 부분은 (기존타입)에 해당하지만,

(새타입이름)에 해당하는 부분이 없으므로 컴파일러는 typedef 부분을 무시하고

그냥 POINT라틑 태그이름으로 구조체를 선언하게 되는 것입니다.

'Programming > C & C++' 카테고리의 다른 글

난수 (Random) 함수  (0) 2008.01.02
pointer 와 reference 의 차이점  (0) 2008.01.02
동적 할당  (0) 2008.01.02
에러시 메모리 값의 의미  (0) 2008.01.02
절대경로 얻기  (0) 2008.01.02

댓글