C언어 고급 문법과 메모리 구조 — 실전 아키텍처 설계
단순히 '코드가 돌아가게' 만드는 단계를 넘어, 메모리가 어떻게 배치(Stack/Heap)되고 여러 개의 소스 파일(.c)과 헤더(.h)가 어떻게 링킹되는지 배웁니다. 엔터프라이즈급 실전 C 프로그래밍을 위한 마지막 관문입니다.
학습 목표
static과 다른 파일의 변수를 참조하는 extern을 이해한다.const int *p 와 int * const p 의 상수성(const) 적용 위치 차이를 명확히 안다.typedef, 상태값을 묶는 enum, 메모리를 공유하는 union을 활용할 수 있다.C 프로그램의 메모리 구조
우리가 작성한 C 코드가 컴파일되어 실행되면, 운영체제는 RAM에 다음과 같이 구역을 나누어 데이터를 배치합니다.
재귀 함수를 너무 많이 호출하거나 배열을 너무 크게 잡으면 Stack 메모리가 꽉 차서 Stack Overflow가 터집니다. 반면, malloc으로 Heap 메모리를 빌린 후 free하지 않으면 쓰레기가 쌓여 컴퓨터가 느려지는 Memory Leak(메모리 누수)이 발생합니다.
static, extern, const 키워드
- static 지역 변수 : 함수가 끝나도 메모리(Data/BSS 영역)에 계속 남아있어 이전 값을 기억합니다.
- static 전역 변수/함수 : 이 변수나 함수를 이 파일 밖(.c)에서 접근하지 못하게(Private) 숨깁니다.
- extern : "이 변수는 다른
.c파일에 선언되어 있으니 찾아봐!" 라고 링커(Linker)에게 알려줍니다.
int value = 10; // 1. 데이터(값) 변경 불가! (포인터가 가리키는 대상이 상수) const int *p1 = &value; // *p1 = 20; (에러발생) // 2. 주소(포인터 자체) 변경 불가! (p2는 평생 value만 가리켜야 함) int *const p2 = &value; // p2 = &other_value; (에러발생)
typedef, enum, union
1. typedef : 복잡한 자료형(구조체나 함수 포인터 등)에 짧은 별명을 붙여줍니다.
2. enum (열거형) : 연관된 상태값(STOP=0, RUN=1, ERROR=2)을 가독성 있게 묶어 관리합니다.
struct(구조체)는 내부에 선언된 모든 변수가 각각의 메모리를 가집니다. 반면 union(공용체)는 가장 큰 변수의 사이즈만큼만 메모리를 할당하고, 모든 변수가 그 메모리 공간을 공유합니다. 임베디드 통신 등에서 데이터를 Byte 단위로 쪼개어 읽을 때 자주 사용됩니다.
소스 분리와 헤더(.h) 파일 모듈화
코드가 1000줄이 넘어가면 모든 것을 main.c에 담을 수 없습니다. C언어는 선언부(.h)와 구현부(.c)를 분리하여 모듈화합니다.
- student.h : 구조체 정의,
typedef, 매크로 정의, 함수 선언(프로토타입)만 작성합니다. - student.c :
#include "student.h"를 하고 함수의 실제 알맹이 로직을 구현합니다. - main.c :
#include "student.h"만 한 뒤, 구현된 함수를 가져다 사용(조립)합니다.
컴파일러는 각각의 .c 파일을 번역하여 오브젝트(.o) 파일을 만들고, 링커(Linker)가 이 .o 파일들을 하나로 묶어 최종 .exe 파일을 만들어 냅니다.
STEP 19 최종 프로젝트
분할 컴파일 기반 학생 관리 시스템
지금까지 배운 typedef struct, 포인터, 동적 할당, 그리고 헤더 분리를 결합하여 3개의 파일(main.c, student.h, student.c)로 동작하는 프로그램을 작성하세요.
- [1] 헤더 가드 :
student.h파일에#ifndef STUDENT_H헤더 가드를 작성합니다. - [2] 구조체 : 헤더에
Student구조체를typedef로 선언합니다. - [3] 포인터 활용 :
student.c에void printStudent(const Student *s)함수를 구현합니다. (const 사용) - [4] 메인 로직 :
main.c에서malloc으로 학생 데이터를 동적 생성한 뒤 출력하고free로 해제합니다.
STEP 19 완료 체크리스트
고생하셨습니다! 이제 C언어 문법이라는 무기를 모두 갖추었습니다. 메모리 구조와 링커의 동작, 헤더 분리 기법까지 이해했다면 실무에서 C언어 코드를 읽는 데 아무런 지장이 없습니다. 이제부터는 "문법을 어떻게 쓰느냐"가 아니라 "이 문법들로 어떤 구조의 소프트웨어를 설계할 것인가"의 문제로 넘어갑니다. 다음 STEP 20. 실전 프로젝트 설계로 나아가 볼까요?