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라틑 태그이름으로 구조체를 선언하게 되는 것입니다.

  1. CalmToT 2009.12.03 16:47 신고

    잘보고갑니다 ^^

    • Favicon of http://finsternis.tistory.com BlogIcon leanu 2009.12.08 09:14 신고

      좋은 정보 알게 되면 같이 공유해요 ㅋㅋ
      방문 감사드립니다.

  2. 기린 2010.07.24 19:33 신고

    아.. 잘보고갑니다. 항상 써왔던건데 이제서야 이해가 훅 되네요 ㅎ 감사합니다.

  3. . 2013.11.11 21:46 신고

    정말 잘보고 갑니다!

  4. Violet 2013.11.26 11:52 신고

    잘보고 갑니다~

  5. Karas 2013.12.20 20:08 신고

    우아 내용이 굿 입니다.

  6. 12시가되면 2014.04.07 10:05 신고

    아항 감사합니다 . 이런한 차이가 있엇군요

  7. 샤이안 2014.04.07 14:55 신고

    감사합니다. 여기저기 찾아보다 여기가 제일 알기 쉬웠어요 ㅋㅋ

  8. bruc2 2014.06.27 14:11 신고

    잘보고 갑니다

  9. PuppyRush 2014.10.22 00:10 신고

    간과하고 넘어갈 부분을 알게 됐네요 감사합니다

  10. BlogIcon 화성인 2015.01.13 10:39 신고

    항상 그냥보고 어 작동하니까 괜찮겠찌 했는데 잘 알고 갑니다 감사합니다!!!

  11. Favicon of http://gyoung822.tistory.com BlogIcon gyoung 2015.05.08 21:53 신고

    당연하게 생각하고 사용했는데
    좋은 글 고맙습니다^^

  12. Favicon of http://davidyu.tistory.com BlogIcon davidyu 2015.11.03 16:28 신고

    잘봤습니다.
    근데 첫번째 두번째 세번째 예제라는 부분부터 이해가 잘 안가네요~~

    • Favicon of http://finsternis.tistory.com BlogIcon leanu 2015.11.11 10:36 신고

      궁금한 부분에 대해 좀 더 구체적으로 말씀 주시면 제가 답변을 해드릴 수 있을거 같습니다. :)

  13. sweetherb100 2017.01.11 16:58 신고

    typedef node *listPtr;
    typedef struct {
    char data;
    listPtr link;
    } node;

    이렇게 써도 되는건가요? (책에 이렇게 나와있는데 너무 헷갈리네요ㅠㅠ)
    두 번째 줄에 typedef struct { } node가 선언되어있기 때문에
    첫번째 줄에서 typedef node *listPtr 이렇게 선언하는 순간,
    node가 뭔지 모를거라 생각해서 저는 안될거라고 생각하거든요~

    • Favicon of http://finsternis.tistory.com BlogIcon leanu 2017.05.11 09:55 신고

      컴파일러에서는 굉장히 다양한 케이스의 소스코드간 구조 파악을 위해 어느정도 문법적 허용을 두는 부분이 있습니다.

      해당 내용에 대한 보다 자세한 설명은 아래의 링크에서 보시면 될꺼 같습니다.

      http://stackoverflow.com/questions/2895209/how-is-it-legal-to-reference-an-undefined-type-inside-a-structure

+ Recent posts