공부했던 자료 정리하는 용도입니다.

재배포, 수정하지 마세요.

 

 


 파일의 분할 

  • static 선언
    * static 전역 변수
    * 함수의 static 변수
  • 헤더 파일
    * #include 지시자의 의미
    * 헤더 파일을 포함하는 방식
  • 구조체 정의
    * 헤더 파일의 중복 삽입 문제

 

파일의 분할

  소스코드 관리의 편의를 위해 각각의 파일에 용도 및 특성별로 함수와 변수를 나눠 저장한다.

 

#include <stdio.h>
int num = 0 ;

void Increment(void)
{
	num++;
}

int GetNum(void)
{
	return num;
}

int main(void)
{
	printf("num : %d \n", GetNum());
	Increment();
	printf("num : %d \n", GetNum());
	Increment();
	printf("num : %d \n", GetNum());
	
	return 0;
}

만약 위와 같은 코드가 있다고 가정하면 아래와 같이 파일을 3개로 분할해서 컴파일하는 것이 가능하다.

 

 

 

num.c

int num = 0 ;

func.c

extern int num;		// int형 변수 num이 외부에 선언되었다고 명시

void Increment(void)
{
	num++;
}

int GetNum(void)
{
	return num;
}

main.c

#include <stdio.h>
extern int num;			// int형 변수 num이 외부에 선언되었다고 명시
extern void Increment(void);	// 함수 void Increment(void)가 외부에 선언되었다고 명시
// void Increment(void)		// 함수가 외부에 선언된 경우는 extern선언 생략가능

int main(void)
{
	printf("num : %d \n", GetNum());
	Increment();
	printf("num : %d \n", GetNum());
	Increment();
	printf("num : %d \n", GetNum());
	
	return 0;
}

  이렇게 3개의 파일로 나눠서 컴파일을 하는 것도 가능하다. 그런데 컴파일러는 파일 단위로 컴파일을 진행하기 때문에 ``extern`` 키워드를 사용해서 변수나 함수가 외부에 선언 및 정의되었다고 명시해주어야 한다. 함수는 키워드를 생략하는 것이 가능하다.

 

 

 

 

Static 선언

  ■ static 전역 변수

  전역 변수에 ``static``을 선언하면 변수의 접근 범위가 파일 내부로 제한된다.(외부 파일에서 접근 불가)

 

 

  ■ 함수의 static 변수

  함수에도 ``static`` 변수를 선언할 수 있다. ``static`` 전역 변수와 마찬가지로 함수의 접근 범위가 파일 내부로 제한되는데, 이때는 @@extern@@ 선언을 하더라도 다른 파일에서는 접근이 불가능하다. 그래서 파일의 외부에서 원치 않게 호출되는 것을 막을 수 있다. 따라서 파일 내부에서만 호출하기 위해 정의된 함수라면 ``extern`` 선언을 추가하여 코드에 안전성을 높이는 것이 좋다.

 

 

 

 

헤더 파일

  외부에 선언된 변수에 접근하거나 외부에 정의된 함수를 호출하기 위한 선언들(``extern``으로 선언된 변수나 함수)을 헤더 파일에 모아놓고 헤더 파일을 포함시키면 더 효율적인 프로그램 제작이 가능하다. 선행 처리기와 매크로의 명령문도 파일 단위로만 유효하기 때문에 헤더 파일에 포함시키는 게 더 효율적인 경우도 있다.

 

 

  ■ #include 지시자의 의미

header1.h

{
	puts("Hello world!");

header2.h

	return 0;
}

main.c

#include <stdio.h>

int main(void)
#include "header1.h"
#include "header2.h"

``#include`` 지시자는 파일의 내용을 단순히 포함시키는 용도로 사용된다.

그래서 위와 같이 3개의 헤더 파일로 분리해서 실행해도 똑같은 결과가 나온다.

 

 

 

  ■ 헤더 파일을 포함하는 방식

#include <헤더파일 이름>			// 표준 헤더파일을 포함시키는 경우 사용
#include "[헤더파일 이름]또는 절대경로"	// 프로그래머가 정의한 헤더파일을 포함시킬때 사용
  1. ``<>``를 이용하는 방식
    : 표준 헤더 파일(기본적으로 제공되는 헤더 파일, 표준 C에 정의되어있다.)이 저장되어 있는 디렉터리에서 파일을 찾는다. 그래서 ``stdio.h``, ``stdlib.h`` ``string.h``와 같은 표준 헤더 파일을 포함시키는 경우에 사용된다.
  2. ``" "``를 이용하는 방식
    : 이 문장을 포함하는 소스파일이 저장된 디렉터리에서 헤더파일을 찾는다. 그래서 프로그래머가 정의한 헤더파일을 포함시키는 경우에 사용된다. 또한 헤더 파일의 이름뿐만 아니라, 드라이브 명과 디렉터리 경로를 포함하는 절대 경로나 상대 경로를 명시해서 헤더 파일을 지정하는 것도 가능하다.

 

   절대경로 

  • window 상의 절대경로 : ``\``로 구분
    ex) ``#include "C:\CPower\Myproject|header.h"``
  • Linux 상에서 절대경로 : ``/``로 구분
    ex) ``#include "/CPower/MyProject/header.h"``

 

   상대경로 

  상대경로를 기반으로 헤더파일을 지정하면 드라이브 명이나 디렉터리 위치에 영향을 덜 받는다.

  • ``../`` : 한 단계 상위 디렉터리를 의미
  • ``./`` : 현재 디렉터리를 의미

 

basicArith.h

// 함수 선언 (사칙연산 기능)
#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

// 헤더파일에 선언했던 함수 정의 (사칙연산 기능)
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;
}

 

areaArith.h

// 함수 선언 (면적을 구하는 기능)
double TriangleArea(double base, double height);
double CircleArea(double rad);

areaArith.c

// 헤더파일에 선언했던 함수 정의 (면적을 구하는 기능)
#include "basicArith.h"	// basicArith.c에 정의되어있는 함수를 사용하기 때문에 포함시켜야함

double TriangleArea(double base, double height)
{
	return Div(Mul(base, height), 2);
}
double CircleArea(double rad)
{
	return Mul(Mul(rad, rad), PI);
}

 

roundArith.h

// 함수 선언 (둘레를 구하는 기능)
double RectangleRound(double base, double height);
double SquareRound(double side);

roundArith.c

// 헤더파일에 선언했던 함수 정의 (둘레를 구하는 기능)
#include "basicArith.h"	// basicArith.c에 정의되어있는 함수를 사용하기 때문에 포함시켜야함

double RectangleRound(double base, double height)
{
	return Mul(Add(base, height), 2);
}
double SquareRound(double side)
{
	return Mul(side, 4);
}

 

main.c

#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;
}

  헤더 파일을 활용하는 예시이다. 헤더파일을 사용하지 않으면 각각의 소스파일에서 호출하는 함수를 ``extern``으로 일일히 포함시켜야 하는데, 헤더파일을 만들었기 때문에 ``#include``문 하나만 사용하면 된다.

 

실행 결과

 

 

 

 

구조체 정의

  구조체의 선언 및 정의는 헤더 파일에 삽입하는 것이 좋다. 그러나 하나의 소스파일 내에서만 사용되는 구조체라면 소스파일에 정의하는 것도 나쁘지 않다.

 

 

  ■ 헤더 파일의 중복삽입 문제

  구조체의 정의는 실행파일의 내용에 직접적인 연관이 있는 정보이므로 구조체의 정의가 포함된 헤더파일의 포함관계를 잘못 설정하면 구조체가 두 번 정의된 형태가 되어 컴파일 에러가 발생한다. 그래서 조건부 컴파일을 활용해서 중복 삽입 문제를 해결한다.

 

 

stdiv.h

#ifndef __STDIV_H__	// __STDIV_H__라는 이름의 매크로가 정의되지 않으면
#define __STDIV_H__

typedef struct div
{
	int quotient;
	int remainder;
}Div;

#endif

 

intdiv.h

#ifndef __INTDIV_H__	// __INTDIV_H__라는 이름의 매크로가 정의되지 않으면
#define __INTDIV_H__

#include "stdiv.h"
Div IntDiv(int num1, int num2);

#endif

intdiv.c

#include "stdiv.h"

Div IntDiv(int num1, int num2)
{
	Div dval;
	dval.quotient = num1 / num2;
	dval.remainder = num1 % num2;
	
	return dval;
}

 

main.c

#include <stdio.h>
#include "intdiv.h"
#include "stdiv.h"

int main(void)
{
	Div val = IntDiv(5, 2);
	printf("몫 : %d \n", val.quotient);
	printf("나머지 : %d \n", val.remainder);
	
	return 0;
}

``#ifndef ~ #endif``를 사용해서 중복 삽입 문제를 방지하는 예시이다.

 

실행 결과

 

 

 

'기타 > C' 카테고리의 다른 글

[C] 비트연산자  (0) 2020.11.07
[C] 매크로와 선행 처리기(Preprocessor)  (0) 2020.06.16
[C] 메모리 구조와 동적할당  (0) 2020.06.15
[C] 공용체(Union Type), 열거형(Enumerated Type)  (0) 2020.06.08
[C] 구조체  (0) 2020.06.01

+ Recent posts