구현한 프로그램의 크기가 커기면 관리하기가 어려워져 문제점이 발생한다. 따라서 여러 개의 파일을 만들어서 서로 연관 있는 함수와 변수들을 구분해서 담는다.
파일을 나누는 이유
- 용도 및 특성 별로 함수와 변수를 나눠서 저장하면 소스코드의 관리가 용이해진다.
컴파일러는 파일 단위로 컴파일을 진행한다. 즉, 다른 파일의 정보를 참조하여 컴파일을 진행하지 않는다.
그래서 선언 및 정의되어 있다고 컴파일러에게 알려주어야 한다.
ex)
num은 외부 파일에 int형으로 선언된 변수 // extern int num; -> int형 변수 num이 외부에 선언되어 있다.
Increment는 반환형과 매개변수의 형이 void인 함수인데, 외부 파일에 정의되어 있다. // extern void Increment(void); -> 함수가 외부에 정의되어 있다. (extern 생략 가능)
extern 선언을 통해 함수 또는 변수가 외부에 선언 및 정의되어 있다는 사실만 알리면 된다.
static 전역변수
- 이 변수는 외부 파일에서의 접근을 허용하지 않는다. ( 이 변수의 접근범위는 파일 내부로 제한한다. )
static int num = 0;
>> static 전역변수는 접근의 범위를 파일의 내부로 제한하는 경우 사용
함수에도 static을 선언할 수 있는데, 이는 마찬가지로 외부 파일에서 호출이 불가능한 함수이다.
static void MaxAdd(void) // 외부 파일에서 호출 불가능한 함수
{
num++;
}
위의 함수는 extern 선언이 되었더라도 다른 파일에서는 접근이 불가능하다.
헤더파일의 디자인
extern int num;
extern int GetNum(void);
. . . .
외부에 선언된 변수에 접근하거나 외부에 정의된 함수를 호출하기 위한 선언들인데, 이들은 둘 이상의 소스파일로 이뤄진 프로그램에서 당연히 삽입될 수 밖에 없는 유형의 선언들이다. 하지만 필요할 때마다 매번 삽입하는 것은 번거로운 일이므로 이들 선언을 헤더파일에 모아두고 필요할 때마다 헤더파일을 포함시키면 된다.
ex)
basicArith.h
1 2 3 4 5 6 7 8 9 10 | #define PI 3.1415 double Add(double num1, double num2); double Min(double num1, double num2); double Mul(double num1, double num2); double Div(double num1, double num2); |
basicArith.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | double Add(double num1, double num2) { return num1+num2; } double Min(double num1, double num2) { return num1-num2; } double Mul(double num1, double num2) { return num1*num2; } double Div(double num1, double num2) { return num1/num2; } |
basicArith.c에는 사칙연산의 기능을 제공하는 함수들이 정의되어 있고, 이 함수들의 선언을 basicArith.h에 모아두었으므로, basicArith.c에 정의된 함수의 호출을 위해서는 헤더파일 basicArith.h를 포함시켜야 한다.
또 한, 매크로의 명령문도 파일 단위로만 유효하기 때문에 매크로 PI에 대한 정의가 헤더파일 basicArith.h에 삽입되었다.
areaArith.h
1 2 3 4 | double TriangleArea(double base, double height); double CircleArea(double rad); |
1 2 3 4 5 6 7 8 9 10 11 12 | #include "basicArith.h" double TriangleArea(double base, double height) { return Div(Mul(base, height), 2); } double CircleArea(double rad) { return Mul(Mul(rad, rad), PI); } |
1 2 3 4 | double RectangleRound(double base, double height); double SquareRound(double side); |
1 2 3 4 5 6 7 8 9 10 11 12 | #include "basicArith.h" double RectangleRound(double base, double height) { return Mul(Add(base, height), 2); } double SquareRound(double side) { return Mul(side, 4); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> #include "areaArith.h" #include "roundArith.h" int main(void) { printf("삼각형 넓이(밑변 4, 높이2):%g \n", TriangleArea(4, 2)); printf("원 넓이(반지름 3): %g \n", CircleArea(3)); printf("직사각형 둘레(밑변 2.5, 높이 5.2): %g \n", RectangleRound(2.5, 5.2)); printf("정사각형 둘레(변의 길이 3): %g \n", SquareRound(3)); return 0; } |
실행결과 : basicArith.c, areaArith.c, roundArith.c, main.c
삼각형 넓이(밑변 4, 높이 2): 4
원 넓이(반지름 3) : 28.2735
직사각형 둘레(밑변 2.5, 높이 5.2) : 15.4
정사각형 둘레(변의 길이 3) : 12
구조체의 중복
구조체 또한 파일단위로 그 선언이 유효하다.
다른 파일의 정보를 참조하여 컴파일을 진행하지 않는다고 하였기 때문에, 구조체에 대한 선언 및 정의는 구조체를 필요로 하는 모든 파일에 존재해야 한다.
하지만 구조체가 중복이 된다면, 컴파일 에러가 발생한다.
(main.c에 stdiv.h가 중복되어 정의가 되었다. stdiv.h 한번, intdiv3.h 두번)
헤더파일을 중복해서 사용한다고 문제가 되지 않는다. 하지만 구조체의 정의는 컴파일을 하는데 도움을 주는 정보가 아닌, 실행파일의 내용에 직접적인 연관이 있는 정보이기 때문에, 이는 에러가 발생한다.
문제 해결 방법은 조건부 컴파일을 활용한다.
ex)
stdiv2.h
1 2 3 4 5 6 7 8 9 10 11 | #ifndef __STDIV2_H__ #define __STDIV2_H__ typedef struct div { int quotient; // 몫 int remainder; // 나머지 } Div; #endif |
1,2 행 10행을 통해서 4 ~ 8 행의 중복삽입을 막고 있다. 1행의 ifndef(__STDIV2_H__가 정의되지 않았더라면 밑의 코드문을 실행한다)가 정의가 되어있지 않은 상태이므로 2행 ~ 8행까지 포함하게 된다. 다음 이 파일을 다시 포함하는 경우에는 매크로 __STDIV2_H__가 정의된 상태이므로 1행ㅇ과 10행에 의해서 그 사이에 있는 모든 내용이 포함되지 않는다.
intdiv4.h
1 2 3 4 5 6 7 8 | #ifndef __INTDIV4_H__ #define __INTDIV4_H__ #include "stdiv2.h" Div IntDiv(int num1, int num2); #endif |
intdiv4.c
1 2 3 4 5 6 7 8 9 10 | #include "stdiv2.h" Div IntDiv(int num1, int num2) { Div dval; dval.quotient=num1/num2; dval.remainder=num1%num2; return dval; } |
main.c
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdio.h> #include "stdiv2.h" #include "intdiv4.h" int main(void) { Div val=IntDiv(5, 2); printf("뮧: %d \n", val.quotient); printf("나머지: %d \n", val.remainder); return 0; } |
'programming > C' 카테고리의 다른 글
C // 선행처리기와 매크로 (0) | 2018.01.08 |
---|---|
C // 메모리 관리, 메모리의 동적할당 (0) | 2018.01.05 |
C // 파일 입출력 (0) | 2018.01.04 |
C // 공용체(Union Type)와 열거형(Enumerated Type) (0) | 2018.01.02 |
C // 구조체와 사용자 정의 자료형2 (0) | 2017.12.30 |