헤더 파일에 무엇이 있고 무엇이 없어야합니까? [닫은]


71

헤더 파일에 절대 포함해서는 안되는 것은 무엇입니까?

예를 들어, 상수가 많은 문서화 된 산업 표준 형식으로 작업하는 경우 헤더 파일로 해당 형식을 정의하는 것이 좋습니다 (해당 형식의 구문 분석기를 작성하는 경우)?

헤더 파일에는 어떤 기능이 들어가야합니까?
어떤 기능을 사용해서는 안됩니까?


1
짧고 고통이 없습니다 : 둘 이상의 모듈에 필요한 정의 및 선언.
ott--

21
이 질문을 "너무 넓다"라고 표시하고 종결하는 것은 절대적으로 수치심을 불러 일으키는 조정의 과잉입니다. 이 질문 은 내가 찾고있는 것을 정확하게 묻습니다. 질문은 잘 구성되어 있으며 매우 명확한 질문을합니다 : 모범 사례는 무엇입니까? 이것이 소프트웨어 엔지니어링에 "너무 광범위"하다면 .. 우리는이 포럼 전체를 닫을 수도 있습니다.
Gewure

TL; 박사. C ++의 경우, Bjarne Stroustrup (작성자)이 작성한 "C ++ 프로그래밍 언어"제 4 판의 섹션 15.2.2에 헤더에 포함해야 할 것과 포함하지 않는 것이 설명되어 있습니다. 질문에 C 태그를 지정했지만 일부 조언도 적용됩니다. 좋은 질문이라고 생각합니다.
horro

답변:


57

헤더에 넣을 내용 :

  • #include헤더가 일부 소스 파일에 포함 된 경우 헤더를 컴파일 할 수 있도록하는 데 필요한 최소 지시문 세트입니다 .
  • 공유해야하고 전처리기를 통해서만 달성 할 수있는 것들의 전 처리기 기호 정의 C에서도 전 처리기 기호는 최소한으로 유지하는 것이 가장 좋습니다.
  • 헤더 본문에서 구조 정의, 함수 프로토 타입 및 전역 변수 선언을 컴파일 할 수있게하는 데 필요한 구조의 전달 선언.
  • 여러 소스 파일간에 공유되는 데이터 구조 및 열거의 정의
  • 링커가 정의를 볼 수있는 함수 및 변수에 대한 선언
  • 인라인 함수 정의이지만 여기서주의하십시오.

헤더에 속하지 않는 것 :

  • 무질서한 #include지시. 이러한 무관심은 재 컴파일 할 필요가없는 것들의 재 컴파일을 야기하며 때때로 시스템이 컴파일 할 수 없도록 만들 수 있습니다. #include헤더 자체에 다른 헤더 파일이 필요하지 않은 경우 헤더에 파일을 넣지 마십시오 .
  • 의도는 전 처리기 이외의 메커니즘, 어떤 메커니즘에 의해 달성 될 수있는 전 처리기 기호.
  • 많은 구조 정의. 그것들을 별도의 헤더로 나눕니다.
  • 추가가 필요 #include하거나 변경 될 수 있거나 너무 큰 함수의 인라인 정의 . 이러한 인라인 함수는 팬 아웃이 거의 없어야하며 팬 아웃이있는 경우 헤더에 정의 된 항목으로 현지화되어야합니다.

최소한의 #include진술은 무엇입니까?

이것은 사소한 질문으로 판명되었습니다. TL; DR 정의 : 헤더 파일에는 직접 사용되는 각 유형을 직접 정의하거나 해당 헤더 파일에 사용 된 각 함수를 직접 선언하는 헤더 파일이 포함되어야하지만 다른 것은 포함해서는 안됩니다. 포인터 또는 C ++ 참조 유형은 직접 사용 자격이 없습니다. 순방향 참조가 선호됩니다.

무료 #include지침을 위한 장소가 있으며 , 이것은 자동화 된 테스트입니다. 소프트웨어 패키지의 모든 헤더 파일에 대해 다음을 자동으로 생성 한 후 컴파일합니다.

#include "path/to/random/header_under_test"
int main () { return 0; }

컴파일은 깨끗해야합니다 (즉, 경고 나 오류가 없어야합니다). 불완전한 유형 또는 알 수없는 유형에 관한 경고 또는 오류는 테스트중인 헤더 파일에 누락 된 #include지시문 및 / 또는 전달 선언이 없음을 의미합니다. 참고 : 테스트 통과라고해서 #include지시어가 충분 하지 않다는 의미는 아닙니다 .


따라서 A라는 구조체를 정의하는 라이브러리가 있고 B라는이 라이브러리가 해당 구조체를 사용하고 라이브러리 B는 프로그램 C에서 사용합니다. 라이브러리 B의 기본 헤더에 라이브러리 A의 헤더 파일을 포함시켜야합니까? 나는 단지 그것을 선언 앞으로? 라이브러리 A는 컴파일하는 동안 라이브러리 B와 컴파일되고 링크됩니다.
MarcusJ

@MarcusJ- 헤더속하지 않는 항목에 나열된 첫 번째 내용은 무의미한 #include 문입니다. 헤더 파일 B가 헤더 파일 A의 정의에 의존하지 않는 경우 헤더 파일 B의 헤더 파일 A를 #include하지 마십시오. 헤더 파일은 타사 종속성을 지정하거나 빌드 지침을 지정할 수있는 곳이 아닙니다. 그것들은 최상위 readme 파일과 같은 다른 곳으로갑니다.
David Hammen

1
@MarcusJ-귀하의 질문에 답변하기 위해 답변을 업데이트했습니다. 귀하의 질문에 대한 답변은 하나도 없습니다. 나는 두 가지 극단으로 설명 할 것이다. 사례 1 : 라이브러리 B가 라이브러리 A의 기능을 직접 사용하는 유일한 위치는 라이브러리 B 소스 파일에 있습니다. 사례 2 : 라이브러리 B는 라이브러리 A에 정의 된 유형 및 / 또는 함수를 직접 사용하여 라이브러리 B에 대한 헤더 파일을 사용하여 라이브러리 A의 기능을 확장 한 것입니다. 사례 1의 경우 라이브러리 A를 공개 할 이유가 없습니다. 라이브러리 B의 헤더. 사례 2의 경우이 노출은 거의 필수입니다.
David Hammen

예 2입니다. 죄송합니다. 라이브러리 B의 헤더에서 라이브러리 A에 선언 된 형식을 사용하고 있다는 사실을 건너 뛰어 죄송합니다. 전달할 수 있다고 생각했지만 제대로 작동하지 않을 것입니다. 업데이트 해 주셔서 감사합니다.
MarcusJ

헤더 파일에 상수를 추가하는 것이 큰 일입니까?
mding5692

15

이미 말한 것 외에도.

H 파일에는 항상 다음이 포함되어야합니다.

  • 소스 코드 문서 !!! 최소한 함수의 다양한 매개 변수 및 리턴 값의 목적은 무엇입니까?
  • 헤더 가드, #ifndef MYHEADER_H #MYHEADER_H 정의 ... #endif

H 파일은 다음을 포함해서는 안됩니다.

  • 모든 형태의 데이터 할당.
  • 기능 정의. 경우에 따라 인라인 함수가 드문 예외 일 수 있습니다.
  • 라벨이 붙은 모든 것 static.
  • 나머지 응용 프로그램과 관련이없는 Typedef, #define 또는 상수

(또한 일정하지 않은 전역 / 외부 변수를 어디에서나 사용해야 할 이유는 없지만 다른 게시물에 대한 토론입니다.)


1
나는 당신이 강조한 것을 제외한 모든 것에 동의합니다. 예를 들어 도서관을 만드는 경우에는 도서관의 사용자 또는 문서를 작성해야합니다. 사내 프로젝트의 경우, 좋은 자체 설명 변수 및 함수 이름을 사용하는 경우 문서로 헤더를 정리할 필요가 없습니다.
martiert

5
@martiert 저는 또한 "코드 자체를 말하게"학교입니다. 그러나 자신 외에는 아무도 사용하지 않더라도 최소한 항상 함수를 문서화해야합니다. 함수에 오류 처리 기능이있는 경우 어떤 오류 코드가 반환되고 어떤 조건에서 실패합니까? 함수가 실패하면 매개 변수 (버퍼, 포인터 등)는 어떻게됩니까? 매우 중요한 또 다른 사항은 포인터 매개 변수가 호출자에게 무언가를 반환하는 것입니다. 즉 할당 된 메모리를 기대합니까? ->

1
호출자에게 함수 내에서 수행되는 오류 처리와 수행되지 않은 작업이 분명해야합니다. 함수가 할당 된 버퍼를 예상하면, 범위를 벗어난 검사도 호출자에게 맡길 가능성이 높습니다. 함수가 실행될 다른 함수에 의존하는 경우이를 문서화해야합니다 (예 : link_list_add () 전에 link_list_init ()를 실행). 마지막으로 함수에 파일, 스레드, 타이머 등을 만드는 것과 같은 "부작용"이있는 경우 설명서에 명시해야합니다. ->

1
"소스 코드 문서"가 여기에 너무 광범위 할 수 있습니다. 이것은 실제로 소스 코드에 속합니다. 입력 및 출력, 사전 및 사후 조건 및 부작용이 포함 된 "사용 설명서"는 서사시가 아니라 간단한 형태로 진행되어야합니다.
보안

2
조금 뒤 늦었지만 문서화는 +1입니다. 왜이 수업이 존재합니까? 코드 자체를 말하지 않습니다 . 이 기능은 무엇을합니까? RTFC (미세한 .cpp 파일 읽기)는 음란 한 네 글자 약어입니다. 이해하기 위해 RTFC를 할 필요는 없습니다. 헤더의 프로토 타입은 추출 가능한 주석 (예 : 독소)으로 인수가 무엇이며 기능이 무엇을 수행하는지 요약해야합니다. 이 데이터 멤버가 존재하는 이유는 무엇이며, 무엇을 포함하며 그 값은 미터, 피트 또는 펄롱입니까? 그것도 (추출 가능한) 의견에 대한 또 다른 주제입니다.
David Hammen

4

나는 결코 결코 말하지 않을 것이지만, 파싱 될 때 데이터와 코드를 생성하는 문장은 .h 파일에 있으면 안됩니다.

매크로, 인라인 함수 및 템플릿은 데이터 또는 코드처럼 보일 수 있지만 구문 분석 할 때 코드를 생성하지 않고 대신 사용할 때 코드를 생성합니다. 이러한 항목은 종종 하나 이상의 .c 또는 .cpp에서 사용해야하므로 .h에 속합니다.

필자의 의견에 따르면 헤더 파일에는 해당 .c 또는 .cpp에 대한 최소한의 실용적인 인터페이스가 있어야합니다. 인터페이스에는 #defines, class, typedef, 구조체 정의, 함수 프로토 타입 및 전역 변수에 대한 덜 선호되는 extern 정의가 포함될 수 있습니다. 그러나 선언이 하나의 소스 파일에서만 사용되는 경우 .h에서 제외되고 대신 소스 파일에 포함되어야합니다.

일부는 동의하지 않을 수 있지만 .h 파일에 대한 개인적 기준은 컴파일 할 수있는 다른 모든 .h 파일을 #include한다는 것입니다. 경우에 따라 이것은 많은 파일이 될 수 있으므로 포함 파일의 큰 트리를 포함하지 않고 클래스의 객체에 대한 포인터를 사용할 수 있도록 클래스에 대한 순방향 선언과 같은 외부 종속성을 줄이는 효과적인 방법이 있습니다.


3

헤더 파일의 구성은 다음과 같습니다.

  • 타입과 상수 정의
  • 외부 객체 선언
  • 외부 함수 선언

헤더 파일에는 객체 정의가 포함되어서는 안되며 형식 정의와 객체 선언 만 포함되어야합니다.


인라인 함수 정의는 어떻습니까?
Kos

인라인 함수가 하나의 C 모듈 내에서만 사용되는 "도우미"함수 인 경우 해당 .c 파일에만 넣으십시오. 인라인 함수가 둘 이상의 모듈에 표시되어야하는 경우 헤더 파일 안에 넣습니다.
theD

또한 라이브러리 경계를 가로 질러 함수를 표시해야하는 경우 라이브러리를 사용하는 모든 사용자가 항목을 수정할 때마다 다시 컴파일해야하므로 인라인으로 만들지 마십시오.
Donal Fellows

@DonalFellows : 백핸드 솔루션입니다. 더 나은 규칙 : 자주 수정 될 수있는 헤더에 물건을 넣지 마십시오. 함수에 팬 아웃이없고 기본 데이터 구조가 변경되는 경우에만 변경되는 명확한 정의가있는 경우 헤더에 짧은 작은 함수를 인라인하는 데 아무런 문제가 없습니다. 기본 구조 정의가 변경되어 함수 정의가 변경되면 모든 것을 다시 컴파일해야하지만 구조 정의가 변경되었으므로 어쨌든 그렇게해야합니다.
David Hammen

0

구문 분석 할 때 데이터 및 코드를 생성하는 명령문은 .h파일 에 없어야 합니다. 필자의 견해로는 헤더 파일에는 해당하는 .c또는 에 대한 실제적인 인터페이스 만 있어야합니다 .cpp.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.