# Uwzględnij w .h lub .c / .cpp?

118

Podczas kodowania w C lub C ++, gdzie powinienem mieć #include?

callback.h:

#ifndef _CALLBACK_H_
#define _CALLBACK_H_

#include <sndfile.h>
#include "main.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data);
void on_button_cancel_clicked(GtkButton* button, struct user_data_s* data);

#endif

callback.c:

#include <stdlib.h>
#include <math.h>

#include "config.h"

#include "callback.h"
#include "play.h"

void on_button_apply_clicked(GtkButton* button, struct user_data_s* data) {
  gint page;
  page = gtk_notebook_get_current_page(GTK_NOTEBOOK(data->notebook));

  ...

Czy wszystkie elementy powinny znajdować się w pliku .h lub .c / .cpp, czy w obu, tak jak to zrobiłem tutaj?

Louise
źródło
2
Pozwól mi to odwrócić i zapytać: co było twoje kryteria decydując się umieścić sndfile.h i main.h w callback.h?
Owen S.

Odpowiedzi:

161

Umieść jak najwięcej w, .ca jak najmniej, w .h. Włączenia w elemencie .csą uwzględniane tylko wtedy, gdy kompilowany jest ten jeden plik, ale .hdołączenia dla elementu muszą być uwzględnione w każdym pliku, który go używa.

Brendan Long
źródło
6
To prawda, ale czy znajdujący się #ifndef _CALLBACK_H_na górze element nie uniemożliwia kompilatorowi przetwarzania go więcej niż jeden raz?
hytromo
11
@ user9379 Zapobiegnie to dołączaniu go więcej niż raz w pliku .c lub .cpp. Każdy plik .c lub .cpp jest generalnie budowany osobno, co oznacza, że ​​.h zostanie ponownie przeanalizowany dla każdego kompilowanego pliku .c lub .cpp.
Brendan Long,
2
Myślę, że głównym powodem umieszczania jak najmniejszej ilości w tym .hjest unikanie w niektórych przypadkach błędu z powodu pętli włączania. Przykład: dwie klasy potrzebują się wzajemnie do implementacji, ale nie do swoich deklaracji. Umieszczenie obu włączeń w .cpps pozwoli uniknąć błędu.
Codoscope
1
@ Qu'est-cet'yont To jest powód, dla którego nie możesz umieścić pewnych rzeczy w plikach .h. Ta odpowiedź dotyczy tego, dlaczego powinieneś umieścić jeszcze mniej.
Brendan Long,
@BrendanLong widzę, chociaż w moim sensie włączenie kilkukrotnie tego samego nagłówka nie ma znaczenia, jeśli umieścisz w nim poprawne makra, aby uwzględnić zawartość tylko raz. Dlatego uważam, że umieszczanie jeszcze mniejszej ilości danych ma na celu zmniejszenie prawdopodobieństwa wystąpienia błędu w przyszłości przy modyfikacji kodu.
Codoscope
55

Jedyny przypadek, w którym powinieneś dołączyć nagłówek do innego pliku .h, to sytuacja, gdy potrzebujesz dostępu do definicji typu w tym nagłówku; na przykład:

#ifndef MY_HEADER_H
#define MY_HEADER_H

#include <stdio.h>

void doStuffWith(FILE *f); // need the definition of FILE from stdio.h

#endif

Jeśli nagłówek A zależy od nagłówka B, tak jak w powyższym przykładzie, nagłówek A powinien zawierać bezpośrednio nagłówek B. Czy nie spróbować zamówić zawiera w pliku .c aby spełnić zależności (czyli w tym nagłówka B przed nagłówka a); to jest wielki stos zgagi, który czeka. Mam to na myśli. Byłem w tym filmie kilka razy i zawsze kończył się płomieniami Tokio.

Tak, może to spowodować wielokrotne dołączanie plików, ale jeśli mają one odpowiednie zabezpieczenia włączające skonfigurowane w celu ochrony przed wieloma błędami deklaracji / definicji, to kilka dodatkowych sekund czasu kompilacji nie jest warte martwienia się. Próba ręcznego zarządzania zależnościami to ból w dupie.

Oczywiście nie powinieneś dołączać plików, których nie potrzebujesz .

John Bode
źródło
10

Umieść jak najwięcej dołączeń w swoim cpp i tylko te, które są wymagane przez plik hpp w hpp. Wierzę, że pomoże to przyspieszyć kompilację, ponieważ pliki hpp będą mniej odsyłacze.

Rozważ również użycie deklaracji przekazywania w pliku hpp, aby jeszcze bardziej zmniejszyć łańcuch zależności dołączania.

Parappa
źródło
1
Oo. Interesująca jest sprawa przedłożonych deklaracji.
Brendan Long
Parappa, deklaracje forward są bardzo przydatne w cyklicznych scenariuszach referencyjnych. Ale czy byłyby dobrą praktyką w innych scenariuszach? (Jestem nowy w C ++, więc szczerze pytam)
Dzyann
5

Jeśli tak #include <callback.h>, nie chcę mieć #includewielu innych plików nagłówkowych, aby skompilować mój kod. W callback.hpowinieneś zawrzeć wszystko, co potrzebne do kompilacji. Ale nic więcej.

Zastanów się, czy użycie deklaracji forward w pliku nagłówkowym (takich jak class GtkButton;) będzie wystarczające, co pozwoli ci zmniejszyć liczbę #includedyrektyw w nagłówku (a co za tym idzie, mój czas kompilacji i złożoność).

Johnsyweb
źródło
Nie zgadzam się. Uwzględnienie całego świata w plikach H zwiększa łańcuch zależności, a tym samym skraca czas kompilacji.
John Dibling
Moja odpowiedź nie zalecała umieszczania całego świata w pliku nagłówkowym, zasugerowałem umieszczenie na tyle tylko , aby użytkownik API nie musiał tracić czasu na szukanie zależności.
Johnsyweb