반응형

 

    C언어는 분할 컴파일이 가능한 언어이다. 분할 컴파일이라고 함은 여러개의 .c 소스를 따로 따로 컴파일하여 .o (object)파일 또는 .a (archieve), .so (shared object), .sl(shared lib) 등으로 만들어서 실행파일을 만들 때에 함께 링크할 수 있다는 것이다. 여러 개의 파일로 분할하거나 기 개발된 라이브러리들을 사용하기 위해서는 그 함수의 정보나 전역변수 등의 정보를 공유해야 하므로 이를 정의한 파일이 header file(.h, .hpp)이다. header file을 만들때에는 기본적인 규칙을 지켜야 오류가 발생하지 않는다. Header 파일을 만들 때에 지켜야 할 사항들을 알아보자.

 

 


Header 파일의 구성

 

header file의 기본 형식 (예: my_lib.h)

#ifndef __MY_LIB_H__ 
#define __MY_LIB_H__

[다른 header 파일 inlcude]

[상수 및 매크로 정의부]

[사용자 정의 type 정의부(struct, union, typedef 등)]

[전역 변수 선언]

[함수 선언부]

#endif

 

1. #ifndef ~ #define ~ #endif

 

#ifndef ~ #endif 문은 header file의 전체를 감싸도록 구성한다.

#ifndef __MY_LIB_H__
#define __MY_LIB_H__

......


#endif

#ifndef {Header 구분자}
#define {Header 구분자}

  ~

#endif

형태로 #ifndef 바로 다음에 #define문을 위치 시킨다.

 

{Header 구분자}의 기본적인 명명규칙은 header 파일명에서 소문자를 대문자로 바꾸고, 온점( . ) 을 undescore ( _ )로 바꾸고 앞뒤로 undescore 2개 ( __ )를 붙인다.

예). 
    utils.h → __UTILS_H__

    my_utils.h → __MY_UTILS_H__
    utils.hpp → __UTILS_HPP__ 

    
#ifndef ~ #define ~ #endif 구조를 갖는 이유는
실수로 header 파일을 2회 include하거나, 간접적(다른 header file내에 include되어 결과적으로는 2번 include하는 경우 등)으로 include 하더라도 중복 선언 등의 문제가 발생하지 않도록 한다. 같은 header file을 2회 include하게 되면 이미 선언된 함수라는 경고 또는 오류가 발생할 수 있으므로 이를 방지할 수 있다.

 

 

2. 다른 header 파일 include

 

Header 파일 내에는 로직 구현이 없으므로 일반적으로 다른 header 파일을 #include 하지 않습니다. 그러나 다른 Header 파일에 선언된 type을 신규로 만들어지는 함수의 parameter나 return으로 사용되는 경우에는 어쩔 수 없이 #include 할 수 밖에 없다. 그 외에는 타 header file을 include해서 사용하지 않는다.

 

예). FILE type을 사용한 경우 

#ifndef __MY_LIB_H__
#define __MY_LIB_H__

#include <stdio.h>

......

int logging(FILE *fp, const char *format, ...);

......

#endif

 

    공통으로 많이 사용하는 Header file에 .c 소스에서 자주 사용하는 .h 파일들을 모두 include하여 .c의 이곳 저곳에서 include를 하지 않고 편하게 사용하는 개발자들이 가끔있는 데, 이는 바람직하지 않다. #include는 자기 자신의 파일 내에서 필요한 것만 해야한다. 그렇지 않으면 프로그램 간의 연관 관계 파악시에 잘못된 정보로 인하여 실제로 사용하지도 않는 데도 불구하고 그 프로그램의 배포 시에 많은 개발자에게 통보를 해야 하는 문제가 발생한다. (영향도 파악 tool 실행 시에도)

 

 

3. 상수 및 매크로 선언부

 

상수 또는 매크로 함수를 선언하는 부분입니다.

C언어에서 상수를 선언하는 방법은 

1. #define으로 선언하기
   #define 상수명 상수값


   ex).

#define PI        3.141592 
#define LEN_NAME  32 


2. const로 선언하기
    const type 상수명 = 상수값;

 

   ex).

const double PI = 3.141592L; 
const int LEN_NAME = 32; 


보통 권고안은 const로 작성하는 것이나 관습이 무서운지 많은 개발자들은 #define으로 선언을 더 선호한다. const를 사용하면 정확한 type을 표현할 수 있어 컴파일 시에 type 체크 등을 해주므로 장점이 많다. 또한  #define을 사용하면 C언어 전처리기(Preprocessor)가 소스에 상수값으로 치환시킨다.

심지어 C 표준 header file에도 상수를 const로 하기보다는 #define을 사용하는 경우가 많다.

 

 

4. 사용자 정의 type 정의부(struct, union, typedef 등)

 

사용자 정의 type을 기술하는 부분이다. 이 부분에는 사용자 정의 type인 struct, union를 정의한다. 또한 향후 OS의 bit수에 따라 type의 길이가 바뀌는 경우를 대비하여 typedef으로 길이를 고정하거나 개발자가 새롭게 만든 struct, union을 쉽게 사용할 수 있도록 typedef합니다.

 

ex).

typedef struct {
    char name[20];
    int  age;
    char gender;
    char addr[128];
    ......
} custom_t;

typdef long int file_size_t;

......

 

 

5. 전역 변수 선언

 

전역변수는 .c에서 정의된 변수를 다른 곳에서도 사용하기 위하여 header 파일에 선언하며, 선언을 할 때에는 반드시 앞에 extern을 붙인다.

 

ex).

extern long gl_total_count;

extern을 붙인다는 것은 gl_total_count라는 변수가 이 파일내에 정의되어 있지않고 다른 파일에 있다라고 선언하는 것이다. header file에 선언된 전역 변수에 extern을 붙이지 않으면, 변수를 선언이 아닌 정의하는 것이다. 이 경우에는 header file을 include한 소스를 분할 컴파일을 하는 경우에 소스마다 전역변수를 정의하는 결과가 되므로 변수 중복 정의에 따른 논리 오류를 유발할 수 있다. 물론, .c 소스 중 어디엔가에는 extern이 붙지 않은 전역변수 정의부가 딱 한곳에 있어야 한다. 당연한 이야기겠지만 staic 변수는 header file에 선언하지 않는다. static 변수는 변수가 정의된 파일 내에서만 참조할 수 있는 변수이므로 사실상 무용지물이다.

 

 

6. 함수 선언부

 

함수의 선언부에는 함수의 prototype을 선언합니다.

 

예를들면,

extern int sum(int i1, int i2);

또는 

extern int sum(int, int);

형식으로 선언합니다. 즉, 함수의 parameter와 return type을 명확하게 선언한다. C언어 컴파일러는 이들 함수를 사용하는 .c 파일을 컴파일 할 때에 잘못 넘겨진 parameter type에 대해서 오류를 발생시키는 역할을 한다.

 

 

참고로

extern int start(void);

extern int start();

는 다른 선언이므로 주의해야 한다.

 

extern int start(void); 는 start()함수의 parameter가 없는 함수라는 의미이지만, extern int start();는 start()함수의 parameter가 무엇인지는 정확하게 밝히기 힘들지만 return이 int인 함수라고 인식하고  컴파일러에게 컴파일할 때에 이해해 달라는 의미이다. 2번째의 extern int start()는 parameter를 명확하게 해두는 것이 바람직하다.

 

 

반응형
블로그 이미지

자연&사람

행복한 개발자 programmer since 1995.

,