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 자료형* 별칭
다음은 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;과 같이 선언해도 됩니다.