Por ejemplo, la herramienta SysInternals "FileMon" del pasado tiene un controlador en modo kernel cuyo código fuente está completamente en un archivo de 4,000 líneas. Lo mismo para el primer programa de ping que se haya escrito (~ 2,000 LOC).
Por ejemplo, la herramienta SysInternals "FileMon" del pasado tiene un controlador en modo kernel cuyo código fuente está completamente en un archivo de 4,000 líneas. Lo mismo para el primer programa de ping que se haya escrito (~ 2,000 LOC).
Respuestas:
El uso de varios archivos siempre requiere una sobrecarga administrativa adicional. Uno tiene que configurar un script de compilación y / o un archivo MAKE con etapas de compilación y vinculación separadas, asegurarse de que las dependencias entre los diferentes archivos se administren correctamente, escribir un script "zip" para facilitar la distribución del código fuente por correo electrónico o descargar, y así en. Los IDE modernos de hoy en día suelen llevar mucha carga, pero estoy bastante seguro de que en el momento en que se escribió el primer programa de ping, no había ningún IDE disponible. Y para archivos tan pequeños como ~ 4000 LOC, sin un IDE que administre múltiples archivos para usted, la compensación entre los gastos generales mencionados y los beneficios del uso de múltiples archivos podría permitir a las personas tomar una decisión sobre el enfoque de un solo archivo.
Porque C no es bueno en la modularización. Se vuelve desordenado (archivos de encabezado e #incluye, funciones externas, errores de tiempo de enlace, etc.) y cuantos más módulos traigas, más complicado será.
Los lenguajes más modernos tienen mejores capacidades de modularización en parte porque aprendieron de los errores de C y hacen que sea más fácil dividir su base de código en unidades más pequeñas y simples. Pero con C, puede ser beneficioso evitar o minimizar todos esos problemas, incluso si eso significa agrupar lo que de otra manera se consideraría demasiado código en un solo archivo.
Además de las razones históricas, hay una razón para usar esto en el software moderno sensible al rendimiento. Cuando todo el código está en una unidad de compilación, el compilador puede realizar optimizaciones de todo el programa. Con unidades de compilación separadas, el compilador no puede optimizar todo el programa de ciertas maneras (por ejemplo, incluir cierto código).
El enlazador ciertamente puede realizar algunas optimizaciones además de lo que puede hacer el compilador, pero no todas. Por ejemplo: los enlazadores modernos son realmente buenos para eludir funciones sin referencia, incluso a través de múltiples archivos de objetos. Es posible que puedan realizar otras optimizaciones, pero nada como lo que un compilador puede hacer dentro de una función.
Un ejemplo bien conocido de un módulo de código fuente único es SQLite. Puede leer más sobre esto en la página de Amalgamación SQLite .
1. Resumen Ejecutivo
Más de 100 archivos de origen separados se concatenan en un solo archivo grande de código C llamado "sqlite3.c" y llamado "la amalgamación". La amalgamación contiene todo lo que una aplicación necesita para incorporar SQLite. El archivo de amalgamación tiene más de 180,000 líneas de largo y más de 6 megabytes de tamaño.
La combinación de todo el código para SQLite en un archivo grande hace que SQLite sea más fácil de implementar: solo hay un archivo para realizar un seguimiento. Y debido a que todo el código está en una sola unidad de traducción, los compiladores pueden hacer una mejor optimización entre procedimientos, lo que resulta en un código de máquina que es entre 5% y 10% más rápido.
$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(CFILES)
que mover todo a un solo archivo soudce. Incluso puede hacer la compilación de todo el programa como un objetivo alternativo al script de compilación tradicional que omite la recompilación de archivos fuente que no han cambiado, de manera similar a cómo las personas pueden desactivar la creación de perfiles y la depuración para el objetivo de producción. No tiene esa opción si todo está en un gran montón de fuentes. No es a lo que la gente está acostumbrada, pero no tiene nada de engorroso.
Además del factor de simplicidad que mencionó el otro encuestado, muchos programas en C están escritos por un individuo.
Cuando tiene un equipo de personas, es deseable dividir la aplicación en varios archivos de origen para evitar conflictos gratuitos en los cambios de código. Especialmente cuando hay programadores avanzados y muy jóvenes trabajando en el proyecto.
Cuando una persona trabaja sola, eso no es un problema.
Personalmente, uso varios archivos basados en la función como algo habitual. Pero solo soy yo.
Porque C89 no tenía inline
funciones. Lo que significaba que dividir su archivo en funciones causó la sobrecarga de empujar valores en la pila y saltar. Esto agregó un poco de sobrecarga sobre la implementación del código en 1 declaración de interruptor grande (bucle de eventos). Pero un bucle de eventos siempre es mucho más difícil de implementar de manera eficiente (o incluso correcta) que una solución más modularizada. Entonces, para proyectos de gran tamaño, las personas aún optarían por modularizar. Pero cuando tenían el diseño pensado de antemano y podían controlar el estado en una declaración de cambio, optaron por eso.
Hoy en día, incluso en C, no es necesario sacrificar el rendimiento para modularizar porque incluso en C las funciones se pueden incorporar.
inline
palabra clave en los compiladores de C89 no podía estar en línea, es por eso que tenía que escribir todo en una función gigante. Casi nunca debería usarlo inline
como una optimización del rendimiento: el compilador generalmente sabrá mejor que usted de todos modos (y puede ignorar la palabra clave).
inline
palabra clave tiene una semántica relacionada con el enlazador que es más importante que la cuestión de si realizar o no las optimizaciones en línea, pero algunas implementaciones tienen otras directivas para controlar la alineación y tales cosas a veces pueden ser muy importantes. En algunos casos, una función puede parecer demasiado grande para que valga la pena incluirla, pero el plegado constante puede reducir el tamaño y el tiempo de ejecución a casi nada. Un compilador al que no se le da un empujoncito para alentar la alineación podría no ...
Esto cuenta como un ejemplo de evolución, que me sorprende que aún no se haya mencionado.
En los días oscuros de programación, la compilación de un solo ARCHIVO podría llevar minutos. Si un programa se modularizó, la inclusión de los archivos de encabezado necesarios (sin opciones de encabezado precompiladas) sería una causa adicional significativa de desaceleración. Además, el compilador podría elegir / necesitar mantener cierta información en el disco, probablemente sin el beneficio de un archivo de intercambio automático.
Los hábitos que estos factores ambientales llevaron a las prácticas de desarrollo en curso y se han ido adaptando lentamente con el tiempo.
En ese momento, la ganancia de usar un solo archivo sería similar a la que obtenemos mediante el uso de SSD en lugar de HDD.