Pregunta

He trabajado con una serie de proyectos de C durante mi carrera de programación y las estructuras de archivos de cabecera por lo general caen en una de estas dos patrones:

  1. Un archivo de cabecera que contiene todos los prototipos de las funciones
  2. Un archivo para cada archivo .h .c, que contiene los prototipos de las funciones definidas en solamente ese módulo.

Las ventajas de la opción 2 son obvias para mí - que hace que sea más barato para compartir el módulo entre múltiples proyectos y hace que las dependencias entre módulos más fáciles de ver

.

Pero ¿cuáles son las ventajas de la opción 1? Se debe tener algunas ventajas de lo contrario no sería tan popular.


Esta pregunta se aplicaría a C ++, así como C, pero nunca he visto # 1 en un proyecto de C ++.

La colocación de #defines, etc. structs también varía, pero para esta pregunta me gustaría centrarse en los prototipos de funciones.

¿Fue útil?

Solución

Opción 1 permite tener todas las definiciones en un solo lugar para que usted tiene que incluir / buscar sólo un archivo en lugar de tener que incluir / search muchos archivos. Esta ventaja es más evidente si su sistema se envía como una biblioteca a un tercero -. Que no les importa mucho acerca de la estructura de su biblioteca, lo que quieren es ser capaz de utilizarlo

Otros consejos

Creo que la principal motivación para el # 1 es ... la pereza. La gente piensa que es demasiado difícil de manejar las dependencias que las cosas división en archivos separados pueden hacer más evidente, y / o pensar que es de alguna manera "exceso" de tener archivos separados para todo.

Puede también, por supuesto, a menudo ser un caso de "razones históricas", en el que el programa o proyecto creció desde algo pequeño, y nadie se tomó el tiempo para refactorizar los archivos de cabecera.

Otra razón para utilizar un .h diferente para cada .c es tiempo de compilación. Si sólo hay un .h (o si hay más de ellos, pero que están incluidos todos ellos en cada archivo .c), cada vez que realice un cambio en el archivo .h, que tendrá que volver a compilar todos los archivos .c. Esto, en un proyecto grande, puede representar una valiosa cantidad de tiempo que se pierdan, que también puede romper el flujo de trabajo.

  • 1 es simplemente innecesario. No puedo ver una buena razón para hacerlo, y hay mucho para evitarlo.

Tres reglas para la siguiente # 2 y no tienen problemas:

  • Comience cada archivo de cabecera con un

    #ifndef _HEADER_Namefile
    #define _HEADER_Namefile_
    

terminar con el archivo

    #endif

Eso le permitirá incluir el mismo archivo de encabezado varias veces en el mismo módulo (innadvertely puede suceder) sin causar ningún problema.

  • no se puede tener definiciones sobre sus archivos de cabecera ... y eso es algo que todo el mundo piensa que él / ella sabe, sobre prototipos de funciones, pero casi nunca hace caso omiso de las variables globales. Si quieres una variable global, que por definición debe ser visible fuera se define el módulo C, utilice la palabra clave extern:

    extern unsigned long G_BEER_COUNTER;
    

que indica al compilador que el símbolo G_BEER_COUNTER es en realidad un largo sin signo (así, funciona como una declaración), que en algún otro módulo tendrá su correcta definición / inicialización. (Esto también permite que el enlazador para mantener la tabla de símbolos resueltos / no resuelto). La definición real (la misma declaración sin extern) va en el archivo del módulo .c.

  • Sólo en la probada necesidad absoluta haces de incluir otras cabeceras dentro de un archivo de cabecera. incluyen declaraciones sólo deben ser visibles en los archivos .c (los módulos). Eso le permite interpretar mejor los dependecies, y encontrar / resolver problemas.

Yo recomendaría un enfoque híbrido: hacer una cabecera separada para cada componente del programa, que posiblemente podría ser utilizado de forma independiente, y luego hacer una cabecera de proyecto que incluye a todos ellos. De esa manera, cada archivo fuente sólo necesita incluir una cabecera (sin necesidad de ir actualizando todos los archivos de origen si refactoriza componentes), pero que mantienen una organización lógica de sus declaraciones y que sea fácil de reutilizar el código.

Hay también creo que una tercera opción: cada uno tiene su propia .c .h, pero también hay una .h que incluye todos los demás archivos .h. Esto trae lo mejor de ambos mundos a expensas de mantener un .h hasta la fecha, a pesar de que podría hacer de forma automática.

Con esta opción, internamente utiliza los archivos .h individuales, sino una tercera parte solo puede incluir el archivo .h que lo abarca todo.

Cuando se tiene un proyecto muy grande con cientos / miles de pequeños archivos de cabecera, y la comprobación de dependencias de compilación pueden ralentizar considerablemente como un montón de pequeños archivos deben ser abiertos y leídos. Este problema puede ser resuelto a menudo mediante el uso de encabezados precompilados.

En C ++ definitivamente desea un archivo de cabecera por clase y utilizar encabezados precompilados como se mencionó anteriormente.

Un archivo de cabecera para un proyecto completo es inviable a menos que el proyecto es extremadamente pequeño - como una tarea escolar

Eso depende de la cantidad de funcionalidad está en un archivo de cabecera / fuente. Si es necesario incluir 10 archivos sólo para, por ejemplo, clasificar algo, es malo.

Por ejemplo, si quiero usar vectores STL acabo de incluir y no me importa lo que son necesarias para el funcionamiento interno vector que se utilizará. GCC de incluye otros 8 cabeceras - asignador, algobase, construir, no inicializado, el vector y bvector. Sería doloroso para incluir a todos los 8 sólo para usar el vector, ¿está de acuerdo?

PERO cabezales internos biblioteca debe ser tan escaso como sea posible. Los compiladores son más felices si no incluyen cosas innecesarias.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top