48.2 typedef로 struct 키워드 없이 구조체 선언하기

구조체 변수를 선언할 때 일일이 struct 키워드를 붙이려니 좀 귀찮습니다. struct키워드를 생략하는 방법은 없을까요? 이때는 typedef로 구조체를 정의하면서 별칭(alias)을 지정해주면 됩니다.

typedef struct 구조체이름 {
    자료형 멤버이름;
} 구조체별칭;

여기서 구조체 이름과 구조체 별칭은 겹쳐도 되지만 이 책에서는 구조체 이름은 _구조체이름처럼 앞에 _를 붙이겠습니다.

typedef로 구조체의 별칭을 만들었다면 변수는 다음과 같이 선언합니다.

  • 구조체별칭 변수이름;

다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

typedef_struct.c

#define _CRT_SECURE_NO_WARNINGS    // strcpy 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h>    // strcpy 함수가 선언된 헤더 파일

typedef struct _Person {   // 구조체 이름은 _Person
    char name[20];            // 구조체 멤버 1
    int age;                  // 구조체 멤버 2
    char address[100];        // 구조체 멤버 3
} Person;                  // typedef를 사용하여 구조체 별칭을 Person으로 정의

int main()
{
    Person p1;    // 구조체 별칭 Person으로 변수 선언

    // 점으로 구조체 멤버에 접근하여 값 할당
    strcpy(p1.name, "홍길동");
    p1.age = 30;
    strcpy(p1.address, "서울시 용산구 한남동");

    // 점으로 구조체 멤버에 접근하여 값 출력
    printf("이름: %s\n", p1.name);       // 이름: 홍길동
    printf("나이: %d\n", p1.age);        // 나이: 30
    printf("주소: %s\n", p1.address);    // 주소: 서울시 용산구 한남동

    return 0;
}

실행 결과

이름: 홍길동
나이: 30
주소: 서울시 용산구 한남동

구조체를 정의할 때 맨 앞에 typedef를 붙여주고 구조체를 정의합니다. 그리고 } (닫는 중괄호)와 ; (세미콜론) 사이에 구조체 별칭을 지정하면 됩니다. 다음은 _Person라는 구조체를 정의하면서 구조체 별칭은 Person로 하겠다는 뜻입니다.

typedef struct _Person {    // 구조체 이름은 _Person
    char name[20];             // 구조체 멤버 1
    int age;                   // 구조체 멤버 2
    char address[100];         // 구조체 멤버 3
} Person;                   // typedef를 사용하여 구조체 별칭을 Person으로 정의

이제 구조체를 사용하려면 변수를 선언해야 합니다. 구조체 별칭을 정의했으므로 struct 키워드는 생략하고 구조체 별칭으로 바로 변수를 선언하면 됩니다.

Person p1;    // 구조체 별칭 Person으로 변수 선언

구조체 별칭으로 선언한 변수도 구조체 멤버에 접근할 때는 . (점)을 사용합니다.

// 점으로 구조체 멤버에 접근하여 값 할당
strcpy(p1.name, "홍길동");
p1.age = 30;
strcpy(p1.address, "서울시 용산구 한남동");

// 점으로 구조체 멤버에 접근하여 값 출력
printf("이름: %s\n", p1.name);       // 이름: 홍길동
printf("나이: %d\n", p1.age);        // 나이: 30
printf("주소: %s\n", p1.address);    // 주소: 서울시 용산구 한남동

만약 구조체 별칭을 사용하지 않고 구조체 이름으로 변수를 선언하고 싶다면 어떻게 해야 할까요? 다음과 같이 struct 키워드에 구조체 이름으로 변수를 선언하면 됩니다.

struct _Person p1;    // 구조체 이름으로 변수 선언

즉, struct _Person p1;Person p1;은 완전히 같습니다.

참고 | typedef 활용하기

typedef는 자료형의 별칭을 만드는 기능입니다. 따라서 구조체뿐만 아니라 모든 자료형의 별칭을 만들 수 있습니다.

  • typedef 자료형 별칭
  • typedef 자료형* 별칭

다음은 int를 별칭 MYINT, int 포인터를 별칭 PMYINT로 정의하는 예제입니다(보통 포인터 별칭은 포인터라는 의미로 앞에 P를 붙임). 별칭으로 변수와 포인터 변수를 선언한다는 점만 다를 뿐 사용 방법은 일반 변수, 포인터와 같습니다.

typedef.c

typedef int MYINT;      // int를 별칭 MYINT로 정의
typedef int* PMYINT;    // int 포인터를 별칭 PMYINT로 정의

MYINT num1;        // MYINT로 변수 선언
PMYINT numPtr1;    // PMYINT로 포인터 변수 선언

numPtr1 = &num1;   // 포인터에 변수의 주소 저장
                   // 사용 방법은 일반 변수, 포인터와 같음       

이처럼 typedef로 정의한 별칭을 사용자 정의 자료형, 사용자 정의 타입이라 부릅니다.

여기서 PMYINT는 안에 *가 이미 포함되어 있으므로 포인터 변수를 선언할 때 *를 붙여버리면 이중 포인터가 되므로 사용에 주의해야 합니다.

PMYINT *numPtr1;    // PMYINT에는 *가 이미 포함되어 있어서 이중 포인터가 선언됨
int* *numPtr2;      // PMYINT *와 같은 의미. 이중 포인터
참고 | 구조체 태그

struct 뒤에 붙는 구조체 이름은 원래 구조체 태그(tag)라 부릅니다(나중에 배울 공용체, 열거형도 마찬가지로 공용체 태그, 열거형 태그라 부릅니다). 그리고 typedef로 정의한 구조체 별칭은 사용자 정의 타입의 이름이라 할 수 있습니다.

struct 태그 {
    자료형 멤버이름;
};

typedef struct 태그 {
    자료형 멤버이름;
} 타입이름;

C 언어는 나온지가 오래되다 보니 여러 가지 관습이 남아 있는데 구조체 태그와 타입 이름을 구분하기 위해 관례상 태그 앞에 _, tag_, tag를 붙이고 있습니다. 코드에 따라서 태그 뒤에 _t를 붙이기도 합니다.

  • 예) _Person, tag_Person, tagPerson, Person_t

구조체 태그와 타입 이름은 사실상 같은 구조체를 지칭하므로 이름을 완전히 다르게 지을 필요는 없습니다. 요즘은 구조체 태그와 타입 이름을 똑같이 만들기도 합니다.

typedef struct Person {    // 구조체 이름은 Person
    char name[20];
    int age;
    char address[100];
} Person;                  // typedef로 정의한 타입 이름도 Person

이때는 구조체 변수를 struct Person p1;과 같이 선언해도 되고 Person p1;과 같이 선언해도 됩니다.