Program Club

헤더에 #include를 사용해야합니까?

proclub 2020. 11. 1. 19:01
반응형

헤더에 #include를 사용해야합니까?


#include헤더 (* .h) 안에이 파일에 정의 된 유형이 사용되는 경우 일부 파일에 필요 합니까?

예를 들어, GLib를 사용하고 gchar헤더에 정의 된 구조에서 기본 유형 을 사용하려면 을 수행해야하는데 #include <glib.h>* .c 파일에 이미 있음을 알고 있어야합니까?

예는 또한 사이에 넣어해야 할 경우 #ifndef#define또는 이후에 #define?


NASA의 GSFC ( Godard Space Flight Center )는 C 헤더에 대한 규칙에 따르면 소스 파일에 헤더를 유일한 헤더로 포함 할 수 있어야하며 해당 헤더에서 제공하는 기능을 사용하는 코드가 컴파일됩니다.

이는 헤더가 자체 포함되고 멱 등성이며 최소 여야 함을 의미합니다.

  • 자체 포함 — 필요한 경우 관련 헤더를 포함하여 필요한 모든 유형을 정의합니다.
  • 멱 등성 — 여러 번 포함되어 있어도 컴파일이 중단되지 않습니다.
  • 최소 — 헤더에 의해 정의 된 기능에 액세스하기 위해 헤더를 사용하는 코드에 필요하지 않은 것은 정의하지 않습니다.

이 규칙의 이점은 누군가 헤더를 사용해야하는 경우 다른 헤더도 포함되어야하는 것을 파악하기 위해 고심 할 필요가 없다는 것입니다. 헤더가 필요한 모든 것을 제공한다는 것을 알고 있습니다.

가능한 단점은 일부 헤더가 여러 번 포함될 수 있다는 것입니다. 이것이 다중 포함 헤더 가드가 중요한 이유입니다 (그리고 컴파일러가 가능할 때마다 헤더를 다시 포함하지 않으려는 이유).

이행

이러한 '등 - 헤더 타입 것을 사용하는 경우이 규칙 수단 FILE *'또는 ' size_t'- 후 적절한 다른 헤더 (확인해야 <stdio.h>또는 <stddef.h>예) 포함되어야한다. 종종 잊혀지는 결과 는 패키지를 사용하기 위해 패키지 사용자가 필요로 하지 않는 다른 헤더를 헤더에 포함해서는 안된다는 것입니다 . 즉, 헤더는 최소한이어야합니다.

또한 GSFC 규칙은 이것이 발생하는지 확인하는 간단한 기술을 제공합니다.

  • 기능을 정의하는 소스 파일에서 헤더는 나열된 첫 번째 헤더 여야합니다.

따라서 Magic Sort가 있다고 가정합니다.

magicsort.h

#ifndef MAGICSORT_H_INCLUDED
#define MAGICSORT_H_INCLUDED

#include <stddef.h>

typedef int (*Comparator)(const void *, const void *);
extern void magicsort(void *array, size_t number, size_t size, Comparator cmp);

#endif /* MAGICSORT_H_INCLUDED */

magicsort.c

#include <magicsort.h>

void magicsort(void *array, size_t number, size_t size, Comparator cmp)
{
    ...body of sort...
}

헤더에는 다음을 정의하는 일부 표준 헤더가 포함되어야합니다 size_t. 가장 적은 수의 표준 헤더 그렇다 <stddef.h>몇몇 다른 사람도 그렇게하지만, ( <stdio.h>, <stdlib.h>, <string.h>, 아마도 몇 가지 다른).

또한 앞서 언급했듯이 구현 파일에 다른 헤더가 필요한 경우에는 그래야하며 일부 추가 헤더가 필요한 것은 전적으로 정상입니다. 그러나 구현 파일 ( 'magicsort.c')은 자체를 포함해야하며 헤더에 의존하여 포함하지 않아야합니다. 헤더에는 소프트웨어 사용자에게 필요한 것만 포함되어야합니다. 구현 자에게 필요한 것이 아닙니다.

구성 헤더

코드에서 구성 헤더 (예 : GNU Autoconf 및 생성 된 'config.h')를 사용하는 경우 'magicsort.c'에서이를 사용해야 할 수 있습니다.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include "magicsort.h"

...

모듈의 개인 헤더가 구현 파일의 첫 번째 헤더가 아님을 아는 유일한 시간입니다. 그러나 'config.h'의 조건부 포함은 아마도 'magicsort.h'자체에 있어야합니다.


2011-05-01 업데이트

위에 링크 된 URL은 더 이상 작동하지 않습니다 (404). 당신의 C ++ 표준 (582-2003-004) 찾을 수 EverySpec.com을 ; C 표준 (582-2000-005)이 작동하지 않는 것 같습니다.

C 표준의 지침은 다음과 같습니다.

§2.1 단위

(1) 코드는 단위 또는 독립형 헤더 파일로 구성되어야합니다.

(2) 유닛은 단일 헤더 파일 (.h)과 하나 이상의 본문 (.c) 파일로 구성됩니다. 헤더 및 본문 파일을 통틀어 소스 파일이라고합니다.

(3) 유닛 헤더 파일은 클라이언트 유닛이 요구하는 모든 관련 정보를 포함해야합니다. 유닛의 클라이언트는 유닛을 사용하기 위해 헤더 파일에만 액세스하면됩니다.

(4) 유닛 헤더 파일은 유닛 헤더에서 요구하는 다른 모든 헤더에 대한 #include 문을 포함해야합니다. 이를 통해 클라이언트는 단일 헤더 파일을 포함하여 단위를 사용할 수 있습니다.

(5) 단위 본문 파일은 다른 모든 #include 문 앞에 단위 헤더에 대한 #include 문을 포함해야합니다. 이를 통해 컴파일러는 필요한 모든 #include 문이 헤더 파일에 있는지 확인할 수 있습니다.

(6) 본문 파일에는 하나의 단위와 관련된 기능 만 포함되어야합니다. 하나의 본문 파일은 다른 헤더에 선언 된 함수에 대한 구현을 제공하지 않을 수 있습니다.

(7) 주어진 유닛 U의 일부를 사용하는 모든 클라이언트 유닛은 유닛 U에 대한 헤더 파일을 포함해야합니다. 이렇게하면 단위 U의 엔터티가 정의 된 위치가 하나만 있습니다. 클라이언트 유닛은 유닛 헤더에 정의 된 함수 만 호출 할 수 있습니다. 그들은 본문에 정의 된 함수를 호출 할 수 없지만 헤더에 선언되어 있지 않습니다. 클라이언트 유닛은 본문에 선언 된 변수에 액세스 할 수 없지만 헤더에는 액세스 할 수 없습니다.

구성 요소는 하나 개 이상의 단위가 포함되어 있습니다. 예를 들어 수학 라이브러리는 벡터, 행렬 및 쿼터니언과 같은 여러 단위를 포함하는 구성 요소입니다.

독립형 헤더 파일에는 연관된 본문이 없습니다. 예를 들어 공통 유형 헤더는 함수를 선언하지 않으므로 본문이 필요하지 않습니다.

한 단위에 여러 본문 파일이있는 몇 가지 이유 :

  • 본문 코드의 일부는 하드웨어 또는 운영 체제에 따라 다르지만 나머지는 일반적입니다.
  • 파일이 너무 큽니다.
  • 이 장치는 일반적인 유틸리티 패키지이며 일부 프로젝트는 일부 기능 만 사용합니다. 각 함수를 별도의 파일에 넣으면 링커가 최종 이미지에서 사용되지 않는 함수를 제외 할 수 있습니다.

§2.1.1 헤더에 근거 포함

이 표준은 유닛 #include헤더에 필요한 다른 모든 헤더에 대한 명령문 을 포함 하는 유닛 헤더를 요구합니다. #include단위 본문에서 단위 헤더를 먼저 배치 하면 컴파일러가 헤더에 모든 필수 #include문이 포함되어 있는지 확인할 수 있습니다 .

이 표준에서 허용하지 않는 대체 디자인 #include은 헤더에 문을 허용하지 않습니다 . 모두 #include들 몸 파일에 수행됩니다. 그러면 단위 헤더 파일에는 #ifdef필요한 헤더가 올바른 순서로 포함되어 있는지 확인하는 문이 포함되어야합니다 .

대체 설계의 한 가지 장점은 #include본문 파일 목록이 정확히 메이크 파일에 필요한 종속성 목록이며이 목록은 컴파일러에 의해 확인된다는 것입니다. 표준 설계에서는 도구를 사용하여 종속성 목록을 생성해야합니다. 그러나 모든 지점에서 권장하는 개발 환경은 이러한 도구를 제공합니다.

대체 설계의 주요 단점은 유닛의 필수 헤더 목록이 변경되면 해당 유닛을 사용하는 각 파일을 편집하여 #include명령문 목록 을 업데이트해야한다는 것 입니다. 또한 컴파일러 라이브러리 유닛에 필요한 헤더 목록은 타겟마다 다를 수 있습니다.

대체 설계의 또 다른 단점은 컴파일러 라이브러리 헤더 파일 및 기타 타사 파일을 수정하여 필요한 #ifdef명령문 을 추가해야한다는 것 입니다.

다른 일반적인 관행은 본문 파일의 프로젝트 헤더 파일 앞에 모든 시스템 헤더 파일을 포함하는 것입니다. 일부 프로젝트 헤더 파일은 시스템 헤더의 정의를 사용하거나 시스템 정의를 재정의하기 때문에 일부 프로젝트 헤더 파일에 의존 할 수 있기 때문에이 표준은이 관행을 따르지 않습니다. 이러한 프로젝트 헤더 파일에는 #include시스템 헤더에 대한 명령문 이 포함되어야합니다 . 본문에 먼저 포함 된 경우 컴파일러는이를 확인하지 않습니다.

인터넷 아카이브를 통해 GSFC 표준 사용 가능 2012-12-10

정보 제공 : Eric S. Bullington :

참조 된 NASA C 코딩 표준은 인터넷 아카이브를 통해 액세스하고 다운로드 할 수 있습니다.

http://web.archive.org/web/20090412090730/http://software.gsfc.nasa.gov/assetsbytype.cfm?TypeAsset=Standard

시퀀싱

질문은 또한 묻습니다.

그렇다면, 나는 또한 (풋해야합니까 #include사이의 라인) #ifndef#define또는 후 #define.

대답은 올바른 메커니즘을 보여줍니다. 중첩 된 포함 등은 뒤에 있어야합니다 #define(그리고 #define헤더에서 주석이 아닌 두 번째 줄이어야 함). 그러나 이것이 올바른 이유를 설명하지 않습니다.

#include사이에 배치하면 어떻게되는지 고려하십시오 . 다른 헤더 자체에 간접적으로 도 다양한 헤더가 포함되어 있다고 가정합니다 . 의 두 번째 포함 이 이전 발생 하면 헤더가 정의하는 유형이 정의되기 전에 헤더가 두 번째로 포함됩니다. 그래서, C89 및 C99에, 어떤 유형 이름이 잘못 (C2011 그들이 동일한 유형으로 재정의 할 수 있습니다) 재정의 될 것이다, 그리고 당신은 먼저 헤더 가드의 목적을 물리 치고, 파일을 여러 번 처리의 오버 헤드를 얻을 것이다 장소. 이것이 두 번째 줄이고 . 주어진 공식은 신뢰할 수 있습니다.#ifndef#define#include "magicsort.h"magicsort.h#define MAGICSORT_H_INCLUDEDtypedef#define#endif

#ifndef HEADERGUARDMACRO
#define HEADERGUARDMACRO

...original content of header — other #include lines, etc...

#endif /* HEADERGUARDMACRO */

A good practice is to only put #includes in an include file if the include file needs them. If the definitions in a given include file are only used in the .c file then include it only in the .c file.

In your case, i would include it in the include file between the #ifdef/#endif.

This will minimize dependencies so that files that don't need a given include won't have to be recompiled if the include file changes.


Usually, library developers protect their includes from multiple including with the #ifndef /#define / #endif "trick" so you don't have to do it.

Of course, you should check... but anyways the compiler will tell you at some point ;-) It is anyhow a good practice to check for multiple inclusions since it slows down the compilation cycle.


During compilation preprocessor just replaces #include directive by specified file content. To prevent endless loop it should use

#ifndef SOMEIDENTIFIER
#define SOMEIDENTIFIER
....header file body........
#endif

If some header was included into another header which was included to your file than it is not necessary to explicitly include it again, because it will be included into the file recursively


Yes it is necessary or the compiler will complain when it tries to compile code that it is not "aware" of. Think of #include's are a hint/nudge/elbow to the compiler to tell it to pick up the declarations, structures etc in order for a successful compile. The #ifdef/#endif header trick as pointed out by jldupont, is to speed up compilation of code.

It is used in instances where you have a C++ compiler and compiling plain C code as shown here Here is an example of the trick:

#ifndef __MY_HEADER_H__
#define __MY_HEADER_H__

#ifdef __cplusplus
extern "C" {
#endif


/* C code here such as structures, declarations etc. */

#ifdef __cplusplus
}
#endif

#endif /* __MY_HEADER_H__ */

Now, if this was included multiple times, the compiler will only include it once since the symbol __MY_HEADER_H__ is defined once, which speeds up compilation times. Notice the symbol cplusplus in the above example, that is the normal standard way of coping with C++ compiling if you have a C code lying around.

I have included the above to show this (despite not really relevant to the poster's original question). Hope this helps, Best regards, Tom.

PS: Sorry for letting anyone downvote this as I thought it would be useful tidbit for newcomers to C/C++. Leave a comment/criticisms etc as they are most welcome.


Just include all external headers in one common header file in your project, e.g. global.h and include it in all your c files:

It can look like this:

#ifndef GLOBAL_GUARD
#define GLOBAL_GUARD

#include <glib.h>
/*...*/
typedef int  YOUR_INT_TYPE;
typedef char YOUR_CHAR_TYPE;
/*...*/
#endif

This file uses include guard to avoid multiple inclusions, illegal multiple definitions, etc.


You need to include the header from your header, and there's no need to include it in the .c. Includes should go after the #define so they are not unnecessarily included multiple times. For example:

/* myHeader.h */
#ifndef MY_HEADER_H
#define MY_HEADER_H

#include <glib.h>

struct S
{
    gchar c;
};

#endif /* MY_HEADER_H */

and

/* myCode.c */
#include "myHeader.h"

void myFunction()
{
    struct S s;
    /* really exciting code goes here */
}

I use the following construct to be sure, that the needed include file is included before this include. I include all header files in source files only.

#ifndef INCLUDE_FILE_H
 #error "#include INCLUDE.h" must appear in source files before "#include THISFILE.h"
#endif

What I normally do is make a single include file that includes all necessary dependencies in the right order. So I might have:

#ifndef _PROJECT_H_
#define _PROJECT_H_
#include <someDependency.h>
#include "my_project_types.h"
#include "my_project_implementation_prototypes.h"
#endif

All in project.h. Now project.h can be included anywhere with no order requirements but I still have the luxury of having my dependencies, types, and API function prototypes in different headers.

참고URL : https://stackoverflow.com/questions/1804486/should-i-use-include-in-headers

반응형