#incluir en .ho .c / .cpp?

118

Al codificar en C o C ++, ¿dónde debería tener los #include's?

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));

  ...

¿Deberían todas las inclusiones estar en .ho .c / .cpp, o en ambos como lo he hecho aquí?

Louise
fuente
2
Permítame darle la vuelta y preguntar: ¿cuál fue su criterio para decidir poner sndfile.hy main.h en callback.h?
Owen S.

Respuestas:

161

Ponga tanto como pueda en el .cy lo menos posible en el .h. Las inclusiones en el .csolo se incluyen cuando ese archivo está compilado, pero las inclusiones para el .hdeben ser incluidas por cada archivo que lo use.

Brendan Long
fuente
6
Es cierto, pero ¿no #ifndef _CALLBACK_H_impide que el compilador lo procese más de una vez?
hytromo
11
@ user9379 Eso evitará que se incluya más de una vez por archivo .co .cpp. Sin embargo, cada archivo .co .cpp generalmente se compila individualmente, lo que significa que se volverá a analizar un .h para cada archivo .co .cpp que compile.
Brendan Long
2
Creo que la razón principal para poner lo menos posible en el .hes para evitar en algunos casos un error debido a un ciclo de inclusión. Ejemplo: dos clases se necesitan entre sí para sus implementaciones, pero no para sus declaraciones. Poner ambas inclusiones en la .cpps evitará un error.
Codoscope
1
@ Qu'est-cet'yont Esa es una razón por la que no puede poner ciertas cosas en los archivos .h. Esta respuesta trata sobre por qué debería poner incluso menos que eso.
Brendan Long
@BrendanLong Ya veo, aunque en mi sentido, incluir varias veces un mismo encabezado no importa si pones las macros correctas dentro para incluir el contenido solo una vez. Por tanto, creo que poner aún menos es reducir las probabilidades de obtener un error en el futuro con modificaciones del código.
Codoscope
55

La única vez que debe incluir un encabezado dentro de otro archivo .h es si necesita acceder a una definición de tipo en ese encabezado; por ejemplo:

#ifndef MY_HEADER_H
#define MY_HEADER_H

#include <stdio.h>

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

#endif

Si el encabezado A depende del encabezado B, como en el ejemplo anterior, entonces el encabezado A debe incluir el encabezado B directamente. No NO tratar de ordenar su incluye en el archivo .c para satisfacer las dependencias (es decir, incluyendo la cabecera B antes de cabecera A); eso es un montón de ardor de estómago esperando suceder. Lo digo en serio. He estado en esa película varias veces y siempre terminaba con Tokio en llamas.

Sí, esto puede resultar en que los archivos se incluyan varias veces, pero si tienen protecciones de inclusión adecuadas configuradas para proteger contra múltiples errores de declaración / definición, entonces no vale la pena preocuparse por unos segundos adicionales de tiempo de compilación. Tratar de gestionar las dependencias manualmente es un dolor de cabeza.

Por supuesto, no debería incluir archivos donde no es necesario .

John Bode
fuente
10

Ponga tantas inclusiones en su cpp como sea posible y solo las que necesita el archivo hpp en el archivo hpp. Creo que esto ayudará a acelerar la compilación, ya que los archivos hpp tendrán menos referencias cruzadas.

También considere usar declaraciones de reenvío en su archivo hpp para reducir aún más la cadena de dependencia de inclusión.

Parappa
fuente
1
Oo. Lo de las declaraciones anticipadas es interesante.
Brendan Long
Parappa, las declaraciones anticipadas son muy útiles en escenarios de referencia circular. Pero, ¿serían una buena práctica en otros escenarios? (Soy nuevo en C ++, así que honestamente pregunto)
Dzyann
5

Si yo #include <callback.h>, no quiero tener #includemuchos otros archivos de encabezado para compilar mi código. En callback.hdebe incluir todo lo necesario para compilar. Pero nada mas.

Considere si el uso de declaraciones hacia adelante en su archivo de encabezado (como class GtkButton;) será suficiente, lo que le permitirá reducir el número de #includedirectivas en el encabezado (y, a su vez, mi tiempo de compilación y complejidad).

Johnsyweb
fuente
Estoy en desacuerdo. Incluir todo el mundo en archivos H aumenta la cadena de dependencia y, por lo tanto, los tiempos de compilación.
John Dibling
Mi respuesta no recomendaba incluir todo el mundo en el archivo de encabezado, sugerí incluir solo lo suficiente para que el usuario de la API no tenga que perder tiempo buscando dependencias.
Johnsyweb