본문 바로가기
프로그래밍 언어/C, C++의 기본적인 설명

[C 언어] 헤더파일 및 분할 컴파일 정리

by UltraLowTemp-Physics 2021. 2. 5.
728x90

A. 헤더 파일

1. 헤더 파일(Header file)이란?

  • 일반적으로 C/C++언어에서는 명령어 및 함수를 정의하고 있는 별도의 파일 (헤더 파일)을 포함한다. 
  • 헤더 파일에서는 다음과 같은 정보를 포함한다. 
     - 사용자가 정의한 구조체 및 공용체의 정의, 데이터형의 정의, 클래스, 함수, 매크로 등의 프로토 타입   
     - 그러나 실제 함수 코드는 헤더 파일이 아니라 컴파일된 코드로 구성된 라이브러리 파일에 들어있음
  • 대표적인 헤더 파일 
     - stdio.h : (Standard Input/Output) 표준 입출력에 관련된 함수들을 정의 
     - math.h : sqrt(), pow(), abs() 등의 수학 관련 함수 정의 
     - stdlib.h : 표준 라이브러리 함수 정의  

 

2. 왜 헤더 파일을 사용해야 하는가?

  • 분할 컴파일을 할 경우, 여러 소스 코드들이 공유해야 할 정보(함수의 프로토 타입, 전역변수)등을 공유하기 위해서 헤더 파일을 사용한다. 
  • 자주 사용하는 함수들의 프로토 타입을 하나의 헤더 파일에 저장을 해두는 것이 코드의 관리에 용이하다. 
ex) 표준 C 라이브러리의, <stdio.h>는 입출력 함수의 프로토 타입이 저장되어 있고, <math.h>에는 수학 함수들의 프로토 타입이 지정되어 있다. 
  • #define과 같은 전처리기를 이용하는 경우, #define 지시자들을 하나의 헤더 파일에 모아 놓고, 각각의 소스 코드에서 #include 지시자를 사용하는 것이 좋다. 
  • 함수 프로토 타입과 기호 상수 정의를 하나의 헤더 파일에 모아 놓는 것은 좋은 프로그래밍 습관이다. 

 

3. 헤더 파일을 만들 때, 지양 해야하는 점 

공통으로 많이 사용하는 헤더 파일에 .c 소스에서 자주 사용하는 .h 파일들을 모두 include하여 .c 파일의 이곳 저곳에서 include를 하지 않고 사용하는 경우가 많은데, 이는 바람직하지 않다. #include는 자기 자신의 파일 내에서 필요한 것만 해야 한다.

 

4.  헤더 파일과 관련된 규칙 및 구성

1) 헤더 파일의 구성
일반적으로 헤더 파일은 아래와 같은 형식을 가진다. 

// The file name of this header file is "awesome_lib.h"


#ifndef __AWESOME_LIB_H__
# define __AWESOME_LIB_H__

<include할 다른 헤더 파일 명시>

<상수 및 메크로 정의>

<사용자 type 정의; type, struct 등..>

<전역 변수 선언>

<함수 선언>

#endif 


• 헤더 파일은 #ifndef/#define/#endif로 감싸져있다. 
   (1) 헤더 파일의 시작은 #ifndef [헤더 구분자]로 시작하여 끝은 #endif로 끝이 난다.  
   (2) #ifndef [헤더 구분자] 바로 다음에는 #define 문을 위치시킨다. 
      - #ifndef와 #define을 아래에서 설명하는 이유 때문에 header gaurd라고 부르기도 한다. 

• 헤더 파일에서는 왜 #ifndef/#endif를 사용하는가? 
 - 위의 전처리기를 사용하는 이유는 다수의 소스코드에서 include된 헤더 파일이 여러 번 포함되는 것을 막기 위한 조치이다.
 - #ifndef 이하에 있는 선언들을 없을 경우 포함시키며, 만일 존재하는 경우, 이미 헤더 파일이 불러진 상태이므로 무시를 한다는 의미
 - 실수로 헤더 파일을 2회 이상 include하는 등의 오류를 피하기 위해서 위와 같은 방법을 사용한다. 

• [헤더 구분자]의 명명 규칙 
 [헤더 구분자]의 명명 규칙은 아래와 같다. 
 - 헤더 파일의 파일명의 모든 영문자는 대문자로 바꾼다. 
 - 온점 "."을 언더바 "_"로 바꾼다. 
 - 파일 이름의 앞 뒤로 두 개의 언더바 "__" 를 붙인다. 
  ex) awesome_lib.h → __AWESOME_LIB_H__ 

 

2) 헤더 파일의 인클루드 :#include <header file> or #include "header file" 
   (1) system에서 제공하는 header file의 경우(표준 ANSI C 라이브러리), "<", ">" 사이에 헤더 파일의 이름을 입력해야 함. 
   (2) 사용자 정의 헤더 파일은 "" 사이에 파일 이름을 입력해야 함. 
      - 별도의 위치를 지정하지 않은 경우, 현재 파일이 있는 위치를 기준으로 해당 헤더 파일을 찾음 
 


B. 분할 컴파일 

1. 분할 컴파일이란? 

C언어는 분할 컴파일이 가능한 프로그래밍 언어이다. 분할 컴파일이란, 여러 개의 c 소스 코드들을 따로 컴파일을 한 후, 여러 파일들*로 만든 후, 해당 파일들을 링크를 하여 실행 파일을 만드는 것이다. 이때, 여러 개로 분할된 파일이나 라이브러리들을 사용하기 위해선, 그 함수의 정보나 전역 변수 등의 정보들을 공유해야 한다. 이러한 공유 해야할 정보들을 정의한 파일이 헤더 파일 (header file, .h, .hpp)이다. 

※ 용어 정리
 (1) 컴파일:
    - 각 소스코드로부터 모듈을 만들어 내는 것 
    - 소스 코드를 중간 코드로 변환 
    - 소스코드를 컴퓨터가 이해할 수 있는 기계어로 변환시키는 과정 
 (2) 링크: 최종적인 통합 작업 
    - 컴파일 과정으로부터 만들어진 중간 코드들을 다른 코드와 결합하여 실행파일로 만듦
    - 시동코드(start-up code), 오브젝트 파일, 라이브러리 파일들을 결합하여 하나의 실행 파일로 만듦 
 (3) 분할 컴파일: 모든 소스코드를 하나의 파일로 작성하는 것 대신 여러 파일로 나누어 작업을 하는 것 
    - C언어에서는 컴파일 및 링크로 분리된 과정을 통해 프로그램의 모듈화가 가능함 
    - 각각의 모듈을 따로따로 컴파일 후, 컴파일된 모듈들을 나중에 링커로 결합이 가능 

*컴파일 시 만들어지는 파일들 
 (1) .o : object file 
 (2) .a : archieve file 
 (3) .so : shared file 
 (4) .sl : shared lib 

* 오브젝트 파일에 대해서 
 - 오브젝트 파일은 단순히 소스코드를 기계어로 변환한 것이며 완전한 프로그램은 아님 
 - 오브젝트 파일은 시동 코드 (start-up code)를 가지고 있지 않음. 시동코드는 프로그램과 운영체제 사이의 인터페이스를 담당한다. 
 - 오브젝트 파일은 라이브러리 루틴을 위한 코드이다. 즉, 특정 함수에 대한 정의를 사용하기 위해선, 해당 함수가 있는 라이브러리와 링크시켜야 한다.  

2. 분할 컴파일의 이점 

 1) 기능 단위의 개발이 가능해짐 
   - 여러 명이 동시에 하나의 파일을 편집하는 것은 다른 복잡한 문제를 야기할 수 있음 
   - 따라서, 기능별로 소스코드를 분할하고, 각 담당자를 할당하여 개발을 진행하는 것이 적합함 
 2) 모듈별 테스트 및 디버깅이 가능해짐 
 3) 필요에 따라 소스코드는 보여주지 않고 모듈만 제공할 수 있음 
 4) 프로그램을 수정하는 경우, 필요한 부분만을 따로 컴파일할 수 있음 
 5) 모듈의 재활용성을 높임 
 6) 프로그램의 가독성을 높임  

3. 헤더 파일과 컴파일 과정

일반적으로 분할 컴파일을 통한 프로그램이 만들어지는 과정은 아래와 같다. 
  (1) 소스코드를 컴파일하여 오브젝트 파일로 만듬

1) 헤더 파일과 컴파일 과정
컴파일을 할 때, 헤더 파일은 직접적으로 오브젝트 파일로 컴파일 되는 것이 아니다. 컴파일러가 #include "사용자 정의 헤더 파일.h" 라인을 컴파일 하면, "사용자 정의 헤더 파일.h"의 내용이 그 라인 시점에 복사된다. 따라서, 일반적으로 헤더 파일이 코드의 앞부분에서 include되므로, 헤더 파일 내의 함수들의 프로토 타입은 함수의 전방선언(Forward declaration)으로 사용된다.  

2) 헤더파일과 함수 및 변수의 구현
헤더 파일에서는 일반적으로 선언만 포함하므로 변수나 함수가 어떻게 구현이 되는지는 정의하지 않는다. 실제 정의는 "링크" 단계에서 자동으로 프로그램에 링크되는 c/c++ 런타임 지원 라이브러리에서 구현이 된다. (아래의 그림 참조). 따라서, 링크를 하는 중에 함수의 구현부를 어떠한 오브젝트 파일에서도 찾지 못할 경우, 에러 메시지가 발생하게 된다.  

 

 


Reference:
[1] https://tragramming.tistory.com/5 
[2] https://tttsss77.tistory.com/59 
[3] https://mong9data.tistory.com/109 
[4] https://velog.io/@two_jay/dd 
[5] https://www.qaupot.com/wordpress/?p=2096
[6] https://www.it-note.kr/7
[7] https://boycoding.tistory.com/144
[8] https://www.tutorialspoint.com/cprogramming/c_header_files.htm

728x90

댓글