C언어 구조체와 공용체, 실기 예제 포함
지금까지 살펴본 변수와 배열은 모두 단일 자료형의 데이터를 다루는 도구였다. 그러나 현실의 데이터는 그렇게 단순하지 않다. 학생 한 명을 표현하려면 학번(정수), 이름(문자열), 학점(실수) 같은 서로 다른 자료형의 정보를 한 묶음으로 관리해야 하며, 이를 가능하게 하는 도구가 바로 구조체(struct)이다. 이와 비슷하면서도 결정적으로 다른 형태인 공용체(union)와 열거형(enum)도 함께 다뤄지며, 세 가지 모두 사용자가 정의하는 새로운 자료형으로 묶인다. 정보처리기사 실기에서도 구조체 멤버 접근과 typedef를 활용한 코드의 출력 결과를 묻는 문제가 자주 출제된다. 본 글은 코드 예시와 함께 세 자료형의 차이를 한 번에 정리한다.

구조체의 선언과 멤버 접근
구조체(Structure)란 서로 다른 자료형의 변수들을 하나의 단위로 묶어 관리하는 사용자 정의 자료형이다. 같은 자료형만 묶을 수 있는 배열과 달리 구조체는 정수·실수·문자·배열·다른 구조체까지 자유롭게 묶을 수 있어 현실의 복합적인 데이터를 표현하기에 매우 적합하다. C언어에서 구조체를 정의할 때는 struct 키워드를 사용하며, 한 번 정의된 구조체는 일반 자료형처럼 사용할 수 있다.
// 구조체 정의
struct Student {
int id;
char name[20];
double gpa;
};
// 변수 선언과 초기화
struct Student s1 = {1, "KIM", 4.5};
// 멤버 접근 — 점(.) 연산자
printf("%d\n", s1.id); // 1
printf("%s\n", s1.name); // KIM
printf("%lf\n", s1.gpa); // 4.500000
// 값 변경
s1.gpa = 4.3;
매번 "struct Student"라고 길게 적는 것이 번거로우니, typedef 키워드를 활용해 별칭을 부여하는 방식이 표준 패턴으로 자리 잡았다. typedef를 쓰면 새 자료형 이름을 일반 자료형처럼 직접 쓸 수 있어 코드가 훨씬 깔끔해진다.
typedef struct {
int id;
char name[20];
double gpa;
} Student;
Student s2 = {2, "LEE", 4.0};
printf("%s\n", s2.name); // LEE
구조체 포인터를 사용할 때는 점(.) 연산자 대신 화살표(->) 연산자를 사용한다. ps->id는 (*ps).id와 동일한 의미이며, 두 표현 모두 같은 결과를 만든다는 사실은 정보처리기사 실기에서 매회 출제되는 핵심 포인트이다.
Student *ps = &s2;
printf("%d\n", ps->id); // 2
printf("%d\n", (*ps).id); // 2 (동일)
구조체는 또한 배열로도 사용할 수 있고, 다른 구조체를 멤버로 가질 수도 있어 매우 유연한 데이터 모델링이 가능하다. 다만 메모리에 저장될 때는 정렬(Alignment) 규칙에 따라 멤버 사이에 패딩(Padding) 바이트가 삽입되기 때문에, 멤버 크기의 단순 합과 sizeof 결과가 다를 수 있다는 점을 기억해야 한다. 일반적으로 가장 큰 멤버의 크기에 맞춰 정렬되며, 이 규칙은 CPU의 효율적인 메모리 접근을 보장하기 위한 것이다.
공용체와 열거형
공용체(Union)는 구조체와 거의 똑같이 보이지만, 결정적인 차이가 하나 있다. 모든 멤버가 같은 메모리 공간을 공유한다는 점이다. 즉 구조체는 모든 멤버를 위한 공간을 따로 할당해 각 멤버가 독립적인 값을 가질 수 있지만, 공용체는 가장 큰 멤버의 크기만큼만 메모리를 할당하고 모든 멤버가 그 공간을 같이 쓴다. 따라서 한 멤버에 값을 쓰면 다른 멤버의 값이 덮어써진다.
union Data {
int i;
float f;
char str[20];
};
union Data d;
d.i = 100;
printf("%d\n", d.i); // 100
d.f = 3.14; // i가 차지하던 공간을 f가 덮어씀
printf("%d\n", d.i); // 쓰레기 값 (3.14의 비트 표현이 정수로 해석됨)
printf("%f\n", d.f); // 3.140000
// sizeof는 가장 큰 멤버 크기 (str 20바이트)
printf("%lu\n", sizeof(d)); // 20
공용체는 메모리를 절약해야 하는 환경이나, 같은 데이터를 여러 형식으로 해석해야 하는 경우에 유용하다. 예를 들어 4바이트 부동소수점의 비트 패턴을 정수로 보고 싶을 때나, 임베디드 환경에서 메모리가 매우 제한적일 때 활용된다. 다만 한 번에 한 멤버만 의미 있는 값을 가진다는 사실을 항상 추적해야 하므로, 일반 응용 프로그래밍에서는 구조체보다 사용 빈도가 훨씬 낮다.
열거형(Enumeration)은 정수 상수에 의미 있는 이름을 부여해 가독성을 높이는 자료형이다. enum 키워드를 사용해 정의하며, 별도로 값을 명시하지 않으면 첫 멤버는 0부터 시작해 1씩 증가하는 정수가 자동으로 부여된다. 명시적으로 값을 지정할 수도 있으며, 이후 멤버는 그 값에서 다시 1씩 증가한다.
enum Day {
MON, // 0
TUE, // 1
WED, // 2
THU, // 3
FRI = 10, // 10
SAT, // 11
SUN // 12
};
enum Day today = WED;
printf("%d\n", today); // 2
printf("%d\n", FRI); // 10
printf("%d\n", SAT); // 11
열거형의 가장 큰 가치는 매직 넘버(Magic Number) 제거이다. 코드에서 0, 1, 2 같은 의미 없는 숫자 대신 MON, TUE, WED 같은 이름을 사용하면 읽는 사람이 그 값의 의도를 즉시 파악할 수 있다. switch 문과 함께 사용하면 상태나 명령을 깔끔하게 분기할 수 있어 모든 분야의 C 코드에서 표준적으로 활용된다.
정보처리기사 실기 빈출 구조체·공용체 예제
정보처리기사 실기에서 구조체와 공용체는 매회 출제되며, 출제 패턴은 다음 네 가지로 정리된다. 각 패턴별 코드를 손으로 추적해보는 연습이 가장 효과적인 시험 대비법이다.
유형 1: 구조체 멤버 접근과 typedef.
typedef struct {
int x;
int y;
} Point;
int main() {
Point p1 = {3, 4};
Point p2;
p2.x = p1.x * 2;
p2.y = p1.y * 2;
printf("%d %d\n", p2.x, p2.y); // 6 8
return 0;
}
typedef로 정의된 구조체를 일반 자료형처럼 사용하고, 멤버를 점 연산자로 접근하는 가장 기본적인 패턴이다.
유형 2: 구조체 포인터와 화살표 연산자.
typedef struct {
int num;
char *name;
} Item;
int main() {
Item it = {10, "apple"};
Item *p = ⁢
printf("%d\n", p->num); // 10
printf("%s\n", p->name); // apple
printf("%c\n", *(p->name)); // a (문자열 첫 글자)
return 0;
}
구조체 포인터의 멤버 접근과 그 멤버가 다시 포인터일 때의 이중 역참조 패턴을 묻는다. *(p->name)이 'a'를 반환하는 이유는 p->name이 "apple"의 첫 글자 주소이기 때문이며, 이 주소를 역참조하면 첫 글자 'a'가 나오는 것이다.
유형 3: 구조체 배열.
typedef struct {
int id;
int score;
} Student;
int main() {
Student arr[3] = {
{1, 85},
{2, 92},
{3, 78}
};
int sum = 0;
for (int i = 0; i < 3; i++) {
sum += arr[i].score;
}
printf("%d\n", sum); // 255
printf("%d\n", arr[1].score); // 92
return 0;
}
구조체 배열을 순회하며 멤버에 접근하는 패턴이다. arr[i].score 형태로 인덱스와 멤버 접근이 결합된다는 점을 정확히 이해해야 한다.
유형 4: 공용체의 메모리 공유.
union Sample {
int a;
char c;
};
int main() {
union Sample s;
s.a = 65; // 'A'의 ASCII 값
printf("%d\n", s.a); // 65
printf("%c\n", s.c); // A (같은 메모리를 char로 해석)
s.c = 'B'; // a의 일부 바이트를 'B'(66)로 덮어씀
printf("%d\n", s.a); // 66 (또는 시스템에 따라 다름)
return 0;
}
공용체에서 한 멤버 변경이 다른 멤버에도 영향을 미친다는 핵심 특성을 묻는 패턴이다. 같은 메모리를 다른 자료형으로 해석하면 어떤 값이 나오는지 추적할 수 있어야 한다.
이 네 가지 패턴을 정확히 이해하면 정보처리기사 실기의 구조체·공용체 영역은 안정적인 점수원이 된다. 결국 구조체는 데이터의 묶음이고, 공용체는 메모리의 공유이며, 열거형은 의미의 명명이라는 세 단어로 요약할 수 있다. 이 세 가지 도구를 적절히 조합해 사용할 줄 알면 코드의 표현력과 가독성이 비약적으로 향상되며, 자료구조와 운영체제의 후속 학습으로 자연스럽게 연결된다.
메타 디스크립션: C언어의 사용자 정의 자료형인 구조체(struct), 공용체(union), 열거형(enum)의 차이와 메모리 동작, typedef를 활용한 별칭 선언, 그리고 정보처리기사 실기 빈출 4패턴을 코드 예시와 함께 정리합니다.