2010-08-14 15 views
33

No entiendo muy bien cómo deben separarse las cosas en los archivos fuente y de encabezado de C. A menudo veo muchos proyectos con dos conjuntos de archivos con el mismo nombre (sin la extensión que denota archivos de origen y de encabezado).Cualquier diferencia fundamental entre los archivos de origen y de cabecera en C?

Hasta ahora, de esta falta de comprensión, cuando escribí bibliotecas, eliminé todo el código de clase y método de clase en un solo archivo, con indecisión en cuanto a elegir la extensión de archivo.

¿Qué debería estar en los encabezados y qué debería estar en los archivos fuente? ¿Cómo implemento esta separación?

Respuesta

43

No hay técnico diferencia. El compilador le dejará felizmente incluir un archivo .c, o compilar un archivo .h directamente, si así lo desea.

Hay, sin embargo, una gran diferencia culturales:

  • Declaraciones (prototipos) ir en .h archivos. El archivo .h es interfaz a lo que se implemente en el archivo correspondiente .c.

  • Definiciones vaya en .c archivos. Ellos implementan la interfaz especificada en el archivo .h.

La diferencia es que un archivo .h puede (y generalmente) ser #include d en múltiples unidades de compilación (.c archivos). Si define una función en un archivo .h, terminará en múltiples archivos .o, y el enlazador se quejará de un símbolo definido de forma múltiple. Es por eso que las definiciones no deben ir en los archivos .h. (Las funciones en línea son la excepción.)

Si una función se define en un archivo .c, y que desea utilizar de otras .c archivos, una declaración de que la función tiene que estar disponible en cada uno de esos otros .c archivos. Es por eso que pone la declaración en un .h, y #include que en cada uno de ellos. También podría repetir la declaración en cada archivo .c, pero eso lleva a una gran cantidad de duplicación de código y un desorden inmaterial.

Si una función se define en un archivo .c, pero No lo quieren usar de otras .c archivos, no hay necesidad de declarar en la cabecera. Básicamente es un detalle de implementación de ese archivo .c. En ese caso, configure la función static también, para que no entre en conflicto con funciones idénticas en otros archivos.

+0

Desafortunadamente, aunque el estándar no exige nada, la mayoría de los compiladores que he usado dependen en cierta medida de la extensión del archivo. Intente esto: cree dos archivos que contengan (digamos, 'int main() {return 0;}') llamados 'header.c' y' header.h' e intente compilarlos con gcc.(¡Ni siquiera me estoy acercando a VS!) – dirkgently

+0

Sospecho que la mayoría de los programadores no ponen las declaraciones de funciones estáticas en el archivo .h. La principal diferencia entre .h y .c es entre la interfaz y la implementación. – Dipstick

+0

@dirkgently: Bien, pero su compilador no actúa como un compilador de C si no obtiene la extensión de archivo correcta. El estándar no dice nada acerca de los programas que no son compiladores de C :) – Thomas

1

Normalmente, los archivos de encabezado contienen declaraciones, los archivos de origen contienen código.

lo tanto, si en el archivo de origen A.c se necesita una función implementada en el archivo de origen B.c, que acaba de incluir B.h tener su declaración.

14

¿Qué debería estar en los encabezados y qué debería contener los archivos fuente?

Normalmente cabeceras contienen uno o más de los siguientes:

  • declaración de la función (excepto la estática)
  • Declaración de variables (típicamente mundial)
  • definido por el usuario declaración de tipo (leer struct, union etc. .)
  • Definición de macro

archivos de origen en otro lado tienen:

  • Función/definición de la variable
  • declaración de la función estática y la definición (que no quiere exponer a éstos a sus clientes)
  • definición variable
  • Algunos prefieren definir las funciones en línea (C99) en una cabecera

¿Cómo implementar esta separación?

La regla de la única definición es tu amigo.

Recuerde, si está escribiendo una biblioteca, esto es lo que su cliente puede ver. Por lo tanto, sea útil y brinde toda la información que pueda para que utilicen su biblioteca. Los archivos fuente generalmente se compilan y se suministran en forma binaria.

Y por cierto, C no tiene el concepto de clases.

+0

'struct' está lo suficientemente cerca para mí :) –

+2

Si" The One Definition Rule "es dorado," Do not tell "es plateado. Con eso quiero decir es que no ponga detalles privados en los archivos de encabezado. Si crea una biblioteca de terceros, todo lo que coloque en el archivo de encabezado debe admitir en el futuro. Si trabaja en proyectos grandes, minimizar los archivos de encabezado promueve la refactorización, ya que reducirá el tiempo de compilación cuando realmente necesite cambiar los archivos de encabezado. (He estado en un proyecto en el que tardó 12 horas en volver a compilar si cambió los archivos del encabezado central. 12hoursx # numberofdevelopers = money) – FuleSnabel

1

Hay una pequeña diferencia fundamental entre los archivos .c y .h (aunque algunos compiladores pueden negarse a compilar un archivo .h sin formato). La diferencia es más por convención.

Normalmente, el archivo .h proporciona la API y .c proporciona la implementación.

Por lo tanto, el archivo .h contendría solo las cosas necesarias para que otros archivos fuente accedan a las instalaciones proporcionadas por su archivo .c. Por lo tanto, los archivos .h proporcionarían los prototipos de función de funciones globales, las declaraciones de variables globales (si realmente las debe tener) y las estructuras y otros tipos utilizados por ellos. (No exponga una estructura si el API solo requiere un puntero a la estructura.)

Las funciones en línea también se incluyen a menudo en archivos .h pero algunas pautas de codificación prefieren el uso de una extensión separada (ej. .inl)

Todas las demás implementaciones de funciones, la definición e inicialización de variables y declaraciones de variables y funciones locales (estáticas) se encontrarían en el archivo .c.

Cuestiones relacionadas