구조체와 사용자 정의 자료형 2

유석현(SeokHyun Yu)·2022년 7월 24일

C

목록 보기
22/26
post-thumbnail

1. 구조체의 정의와 typedef 선언

구조체 변수를 선언할 때에는 무조건 struct 선언을 추가해야 한다.

하지만 이것이 여간 귀찮은 게 아니다.

int형 변수 num을 선언할 때 그저 int num 이라 선언하듯이, person 형 구조체 변수 man을 선언할 때에도 struct 선언 없이 그냥 person man 이라 하고 싶다.

그렇다면 구조체를 정의한 후에 typedef 선언을 추가해야 한다.


먼저 typedef 선언이 무엇인지 살펴보자.

typedef 선언은 기존에 존재하는 자료형의 이름에 새 이름을 부여하는 것을 목적으로 하는 선언이다.

예를 들어서 다음과 같이 typedef 선언을 하게 되면,

typedef int Int;

int num1;
Int num2;

위 두 선언 모두 int형의 변수를 선언하는 것과 같다.

이러한 typedef 선언을 통해서, 복잡한 유형의 자료형 선언을 매우 간결히 처리할 수 있다.

그래서 대부분의 프로그램 개발에 있어서 적지 않은 typedef 선언이 항상 포함된다.

그리고 typedef로 정의되는 자료형의 이름은 대문자로 시작하는 것이 관례이다.

그래야 기본 자료형의 이름과 typedef로 새로이 정의된 자료형의 이름을 구분할 수 있기 떄문이다.


#include <stdio.h>

struct point
{
	int xpos;
	int ypos;
};

typedef struct point Point;

typedef struct person
{
	char name[20];
	int age;
} Person;

int main(void)
{
	Point pos={10,20};
	Person man={"홍길동", 20}; 
	
	return 0;
}

typedef 를 통해 구조체 자료형을 정의하는 방법은 위 코드에서 볼 수 있듯이 2가지가 있다.

그리고 typedef 선언이 추가되었다고 해서 struct 선언을 통한 구조체 변수의 선언이 불가능한 것은 아니다.


앞서 보인 코드에서는 구조체 person을 다음의 형태로 정의하였다.

typedef struct person
{
   char name[20];
   int age;
} Person;

그리고 이렇게 정의가 되면, 구조체의 이름 person은 사실상 별 의미를 갖지 않게 된다.

구조체 변수를 선언할 때 typedef에 의해 정의된 이름 Person을 사용하기 때문이다.

따라서 다음과 같이 구조체의 이름을 생략하는 것도 가능하다.

typedef struct
{
   char name[20];
   int age;
} Person;

단, 이와 같이 구조체의 이름을 생략하면, struct person man과 같은 형태로는 구조체 변수를 선언할 수 없다.


2. 함수로의 구조체 변수 전달과 반환

#include <stdio.h>

typedef struct point
{
	int xpos;
	int ypos;
} Point; 

void Show(Point pos)
{
	printf("%d, %d", pos.xpos, pos.ypos);
}

int main(void)
{
	Point pos={10,20};
	Show(pos);
	
	return 0;
}

구조체도 함수의 인자로 전달될 수 있다.


#include <stdio.h>

typedef struct point
{
	int xpos;
	int ypos;
} Point; 

void Show(Point* pos)
{
	printf("%d, %d", pos->xpos, pos->ypos);
}

int main(void)
{
	Point pos={10,20};
	Show(&pos);
	
	return 0;
}

Call-By-Reference 형태의 구조체 변수 전달


#include <stdio.h>

typedef struct point
{
	int xpos;
	int ypos;
} Point; 

int main(void)
{
	Point pos1={10,20};
	Point pos2;
	
	pos2=pos1;
	
	return 0;
}

구조체 변수로 대입 연산, 즉 복사가 가능하다.

그 이외의 연산은 불가능하다.


#include <stdio.h>

typedef struct point
{
	int xpos;
	int ypos;
} Point; 

typedef struct circle
{
	Point cen;
	double rad;
} Circle;

void Show(Circle* cptr)
{
	printf("%d, %d", (cptr->cen).xpos, (cptr->cen).ypos);
	printf("%g\n", cptr->rad);
}

int main(void)
{
	Circle c1={{1, 2}, 3.5};
	Circle c2={1, 2, 3.5};
	
	Show(&c1);
	Show(&c2);
	
	return 0;
}

구조체 변수가 멤버로 존재할 경우, 중괄호를 이용해서 구조체 멤버의 초기화를 구분지을 수 있다.

중괄호를 이용해서 구조체 변수의 초기화를 구분 짓지 않으면, 순서대로 초기화 된다.


3. 공용체(Union Type)의 정의와 의미

typedef union point
{
	int xpos;
	int ypos;
} Point; 

구조체에서 struct 대신 union만 넣으면 '공용체'가 된다.


위 그림에서 보이듯이 구조체 변수가 선언되면, 구조체를 구성하는 멤버는 각각 할당이 된다.

반면 공용체 변수가 선언되면, 공용체를 구성하는 멤버는 각각 할당되지 않고, 그 중 크기가 가장 큰 멤버의 변수만 하나 할당되어 이를 공유하게 된다.

이러한 특성의 확인을 튀해서 다음 코드를 관찰하자.

#include <stdio.h>

typedef union ubox
{
	int mem1;
	int mem2;
	double mem3;
} UBox;

int main(void)
{
	UBox ubx;
	ubx.mem1=20;
	printf("%d \n", ubx.mem2); // 20
	
	ubx.mem3=7.15;
	printf("%d \n", ubx.mem1); // -1717986918
	printf("%d \n", ubx.mem2); // -1717986918
	printf("%g \n", ubx.mem3); // 7.15
	
	return 0;
}

ubx.mem1에서 상위 4바이트 메모리 공간에 20을 저장한다.

mem2int형 변수이므로 이 이름으로 접근할 경우 상위 4바이트의 메모리 공간을 참조하게 된다.

앞서 이 공간에 20을 저장했으므로 20이 정상적으로 출력된다.

그 다음, mem37.15 실수를 저장하고 있다. 결과적으로 20을 덮어써버리게 된다.

실수를 저장하면서 덮어써버렸기 때문에, 상위 4바이트를 읽어서 출력하면 알 수 없는 값이 출력된다.

따라서 7.15를 저장하고 mem3을 출력하려고 할 때만 정상적으로 출력이 된다.


4. 열거형(Enumerated Type)의 정의와 의미

#include <stdio.h>

typedef enum syllable
{
	Do=1, Re=2, Mi=3
} Syllable;

int main(void)
{
	Syllable tone;

	tone=Do;
	
	printf("%d", tone);
	
	return 0;
}

위의 열거형 정의에서는 Do, Re, Mi라는 이름의 상수를 각각 1, 2, 3으로 정의하고, 이 값들을 Syllable형 변수가 저장할 수 있는 값들로 제한한 것이다.

또한 다음의 의미를 지닌다.

"Do를 정수 1을 의미하는 상수로 정의한다. 그리고 이 값은 Syllable형 변수에 저장이 가능하다."


열거형을 정의하는데 있어서 상수의 값을 명시하지 않으면, 열거형 상수의 값은 어떻게 결졍이 될까?

enum color
{
   RED, BLUE, WHITE, BLACK
};

위 정의에는 열거형 상수의 이름만 선언되었을 뿐 상수의 값은 선언되어 있지 않다.

이러한 경우 열서형 상수의 값은 0에서부터 시작해서 1씩 증가하는 형태로 결정이 된다.

즉 위의 정의는 다음의 정의와 완전 동일하다.

enum color
{
   RED=0, BLUE=1, WHITE=2, BLACK=3
};

이번에는 정의 형태가 조금 다른 예를 보자.

enum color
{
   RED=3, BLUE, WHITE=6, BLACK
};

이 정의에서는 열거형 상수 BLUEBLACK의 값이 선언되어 있지 않다.

그러나 값이 선언되지 않으면 앞서 선언된 상수보다 1이 증가된 값이 할당된다.

즉 위의 정의는 다음의 정의와 완전히 동일하다.

enum color
{
   RED=3, BLUE=4, WHITE=6, BLACK=7
};

열거형의 유용함은 둘 이상의 연관이 있는 이름을 상수로 선언함으로써 프로그램의 가독성을 높이는데 있다.

profile
Backend Engineer

0개의 댓글