Respuestas:
Si se usa correctamente, esta puede ser una técnica útil.
Supongamos que tiene un subsistema complejo y de rendimiento crítico con una interfaz pública bastante pequeña y una gran cantidad de código de implementación no reutilizable. El código se ejecuta en varios miles de líneas, un centenar de funciones privadas y bastante información privada. Si trabaja con sistemas integrados no triviales, probablemente se enfrente a esta situación con la suficiente frecuencia.
Su solución probablemente será en capas, modular y desacoplada y estos aspectos se pueden representar y reforzar de manera útil codificando diferentes partes del subsistema en diferentes archivos.
Con C, puede perder mucho al hacer esto. Casi todas las cadenas de herramientas proporcionan una optimización decente para una sola unidad de compilación, pero son muy pesimistas acerca de cualquier cosa declarada externa.
Si pones todo en un módulo fuente C, obtienes:
Mejoras en el rendimiento y el tamaño del código: las llamadas a funciones se incluirán en muchos casos. Incluso sin la inserción, el compilador tiene oportunidades para producir código más eficiente.
Ocultación de funciones y datos de nivel de enlace.
Evitar la contaminación del espacio de nombres y su corolario: puede usar nombres menos difíciles de manejar.
Recopilación y vinculación más rápidas.
Pero también obtiene un lío profano cuando se trata de editar este archivo y pierde la modularidad implícita. Esto se puede solucionar dividiendo la fuente en varios archivos e incluyéndolos para producir una sola unidad de compilación.
Sin embargo, debe imponer algunas convenciones para administrar esto correctamente. Estos dependerán de su cadena de herramientas hasta cierto punto, pero algunos consejos generales son:
Coloque la interfaz pública en un archivo de encabezado separado; debería hacerlo de todos modos.
Tenga un archivo .c principal que incluya todos los archivos .c subsidiarios. Esto también podría incluir el código de la interfaz pública.
Utilice protecciones del compilador para asegurarse de que las unidades de compilación externas no incluyan encabezados privados y módulos fuente.
Todos los datos y funciones privados deben declararse estáticos.
Mantenga la distinción conceptual entre archivos .cy .h. Esto aprovecha las convenciones existentes. La diferencia es que tendrá muchas declaraciones estáticas en sus encabezados.
Si su cadena de herramientas no impone ningún motivo para no hacerlo, asigne un nombre a los archivos de implementación privados como .cy .h. Si usa protectores de inclusión, estos no producirán código ni introducirán nombres nuevos (puede terminar con algunos segmentos vacíos durante el enlace). La gran ventaja es que otras herramientas (por ejemplo, IDE) tratarán estos archivos de manera adecuada.
¿está bien? sí, se compilará
es recomendado no: los archivos .c se compilan en archivos .obj, que se vinculan entre sí después de la compilación (por el vinculador) en el ejecutable (o biblioteca), por lo que no es necesario incluir un archivo .c en otro. Lo que probablemente quiera hacer en su lugar es crear un archivo .h que enumere las funciones / variables disponibles en el otro archivo .c e incluir el archivo .h
No.
Dependiendo de su entorno de compilación (no lo especifica), puede encontrar que funciona exactamente de la manera que desea.
Sin embargo, hay muchos entornos (tanto IDE como muchos Makefiles hechos a mano) que esperan compilar * .c; si eso sucede, probablemente terminará con errores de vinculador debido a símbolos duplicados.
Por regla general, esta práctica debe evitarse.
Si es absolutamente necesario #incluir la fuente (y generalmente debe evitarse), use un sufijo de archivo diferente para el archivo.
Pensé en compartir una situación en la que mi equipo decidió incluir archivos .c. Nuestra arquitectura consta en gran parte de módulos desacoplados mediante un sistema de mensajes. Estos controladores de mensajes son públicos y llaman a muchas funciones de trabajadores estáticos locales para que hagan su trabajo. El problema surgió al intentar obtener cobertura para nuestros casos de prueba unitaria, ya que la única forma de ejercitar este código de implementación privado era indirectamente a través de la interfaz de mensajes públicos. Con algunas funciones de los trabajadores hasta las rodillas en la pila, esto resultó ser una pesadilla para lograr una cobertura adecuada.
La inclusión de los archivos .c nos dio una forma de llegar al engranaje de la máquina que estábamos interesados en probar.
Puede usar el compilador gcc en linux para vincular dos archivos c en una salida. Suponga que tiene dos archivos c, uno es 'main.c' y otro es 'support.c'. Entonces, el comando para vincular estos dos es
gcc main.c support.c -o main.out
De este modo, dos archivos se vincularán a una única salida main.out Para ejecutar la salida, el comando será
./main.out
Si está usando la función en main.c que está declarada en el archivo support.c, entonces debe declararla en main también usando la clase de almacenamiento extern.
La extensión del archivo no es importante para la mayoría de los compiladores de C, por lo que funcionará.
Sin embargo, dependiendo de la configuración de su archivo MAKE o proyecto, el archivo c incluido puede generar un archivo de objeto separado. Al vincular, eso puede conducir a símbolos de doble definición.
Puede incluir correctamente archivos .C o .CPP en otros archivos de origen. Dependiendo de su IDE, generalmente puede evitar el doble enlace mirando las propiedades de los archivos de origen que desea incluir, generalmente haciendo clic derecho sobre él y haciendo clic en propiedades, y desmarcar / marcar compilar / vincular / excluir de la compilación o cualquier opción tal vez. O no podría incluir el archivo en el proyecto en sí, por lo que el IDE ni siquiera sabrá que existe y no intentará compilarlo. Y con los archivos MAKE simplemente no pondría el archivo en él para compilar y vincular.
EDITAR: Lo siento, hice una respuesta en lugar de una respuesta a otras respuestas :(
El lenguaje C no prohíbe ese tipo de #include, pero la unidad de traducción resultante aún debe ser C.
No sé qué programa estás usando con un archivo .prj. Si está usando algo como "make" o Visual Studio o lo que sea, solo asegúrese de configurar su lista de archivos para que se compilen sin el que no se puede compilar de forma independiente.
La inclusión de un archivo C en otro archivo es legal, pero no es recomendable, a menos que sepa exactamente por qué está haciendo esto y qué está tratando de lograr.
Estoy casi seguro de que si publicas aquí la razón por la que detrás de tu pregunta la comunidad te encontrará otra forma más apropiada de lograr tu objetivo (por favor, ten en cuenta el "casi", ya que es posible que esta sea la solución dado el contexto ).
Por cierto, me perdí la segunda parte de la pregunta. Si el archivo C se incluye en otro archivo y al mismo tiempo se incluye en el proyecto, probablemente terminará con un problema de símbolo duplicado por qué vincular los objetos, es decir, la misma función se definirá dos veces (a menos que todos sean estáticos).