지금까지 만들었던 대부분의 코드들은 비교적 짧았을 것입니다. 하지만 실제로 기업같은곳에서 사용하는 프로그램을 만들기 위해서는 수천줄, 수만줄이 넘는 코드가 사용된다고 합니다. 이렇게 긴 코드들을 관리하기 위해서는 이 소스코드들을 여러 파일로 나누어 관리하는것이 필요하겠죠?
자, 그렇다면 이렇게 여러 파일로 나누기 위해서는 어떻게 해야할까요?
우선 우리의 코드가 실행되는 main()
함수가 존재하는 main.cpp
의 파일이 있을것입니다. 그리고 이 main.cpp
와 같은 디렉토리(폴더)안에 우리가 만든 함수나 구조체 같은 코드들을 담을 파일을 만들어 사용해야 합니다.
이를 위해서, 헤더파일과 구현파일이 존재합니다.
우선 헤더파일은 그 헤더파일을 가져오는 파일에게 사용하고자 하는 것의 존재를 알려주는 역할을 한다고 생각합시다.
구현파일은 이 헤더파일에서 알려준 것이 실제로 구현되어 있는 파일입니다.
우선 #include
전처리는 그 자리에 해당 헤더파일이 있는것처럼 작동하도록 합니다.
즉, #include <iostream>
이란 코드는 이 자리에 해당 iostream
이 있는것처럼 작동하도록 도와줍니다.
"이 자리에"라는 말을 기억해주셨으면 좋겠습니다.
- 이 말인 즉슨 전처리의 순서가 중요하다는 것입니다. 만약 a라는 파일에서 b파일에 정의된 내용을 사용한다고 가정해 봅시다. 이 때 b를 먼저 불러오지 않고, a를 불러오게되면 이 a는 b의 존재를 모르고 있기 때문에 오류를 일으키게 됩니다.
- 또 같은 이름의 함수
void testa(int a);
를 가지고 있는 헤더 파일이 a, b두개가 있다고 가정해 봅시다. 이 때main.cpp
파일에서 이 두 파일을#include
한 후에testa()
함수를 사용한다면, 이 함수가 a에있는 함수인지, b에 있는 함수인지 판단할 방법이 없으므로 오류를 일으키게 됩니다.
- 또 같은 헤더파일을 두번
#include
할 경우 중복정의가 되므로 오류를 일으키게 됩니다.
이렇게 #include
를 통해 사용하고자하는 함수의 원형(prototype)이 있는 헤더파일을 불러오면, 컴퓨터는 "아, 이러한 함수가 있구나"라고 생각하게 되고 후에 이 함수를 사용할 때, 그 함수의 내용을 .cpp
파일들에서 찾아보게되고 실행할 수 있게 됩니다.
#include < >
와, #include " "
의 차이
- 확장자:
.h
- 파일이름:
구현파일
(파일이름을 구현파일과 같이 하는것은 후에 헷갈리지 않도록 하기 위한 권장사항 입니다.)
- 예시:
point.h
- 중복방지 심볼
소스파일이 아주 많아지면 파일간의 포함관계가 복잡해질 수 있습니다.
이때 같은 헤더파일을 두번 포함하는 경우가 생길 수 있는데 이 경우 위에서 설명한 이유로 인해 오류를 일으키게 됩니다.
이를 방지하기 위해 다음의 방법이 있습니다.
#ifndef POINT_H // 해석: if not define POINT_H, // 즉, 만약 POINT_H심볼이 정의되어 있지 않으면 #define POINT_H // 해석: define POINT_H // 즉, POINT_H 심볼을 정의한다. #endif
(비쥬얼 스튜디오의 경우 같은 역할을 하는 다음의 전처리기를 지원합니다.)
#pragma once
- 함수의 프로토 타입
double distance(point& x, point& y);
- 구조체의 정의
struct point { int x, y; }
파일이름: point.h
파일내용
#ifndef POINT_H
#define POINT_H
struct point {
int x, y;
};
double distance(point& x, point& y);
#endif
헤더파일에는 inline함수만 존재해야 합니다.
참고로 class의 멤버 함수들은 inline으로 작동합니다.
<< 연산자 오버로딩을 할 때 이로인해서 작동되지 않는 경우가 존재합니다.
- 확장자:
.cpp
- 파일 이름:
구현파일
(구현파일의 이름은 이 파일안에 담긴 내용을 대표할 수 있는 단어로 하는것이 좋겠죠)
- 예시:
point.cpp
- 전처리
구현에 필요한 파일들을 미리 전처리하여 가져옵니다.
#include <iostream> // 사용할 헤더파일 #include "abcd.h" // 사용할 헤더파일 #include "point.h" // 자기 자신의 헤더파일
(이 때 이 구현파일 안의 함수가 서로 호출할 경우 그 순서에 따라 문제가 발생할 수 있습니다. 이를 방지하기 위해서 자기 자신의 헤더파일을
#include
해주는 것이 좋습니다.)
- 함수 구현
이제 헤더파일에서 정의한 프로토 타입 함수들을 구현해 줍시다.
double distance (point& x, point& y) { ~ }
파일이름: point.cpp
파일 내용
#include <iostream>
#include <cmath>
#include "point.h"
double distance(point& x, point& y) {
함수 내용
}
자 마지막으로 정리해 보면 헤더파일에는
그리고 구현파일에는
이 들어가게 될 것입니다.