¿Qué métodos, prácticas y convenciones conoces para modularizar el código C a medida que crece el tamaño de un proyecto?¿Qué métodos existen para modularizar el código C?
Respuesta
Hay directorios y archivos, pero no espacios de nombres ni encapsulamiento. Puede compilar cada módulo en un archivo obj separado y vincularlos (como bibliotecas).
¿qué ocurre con la creación de DLL que contienen funcionalidades relacionadas? –
Una DLL es un tipo de biblioteca. –
Romper el código en bibliotecas de funciones relacionadas es una forma de mantener las cosas organizadas. Para evitar conflictos de nombres, también puede usar prefijos para permitirle reutilizar los nombres de las funciones, aunque con buenos nombres nunca he encontrado realmente que esto sea un gran problema. Por ejemplo, si desea desarrollar sus propias rutinas matemáticas pero todavía utiliza algunas de la biblioteca matemática estándar, puede prefijar las suyas con alguna cadena: xyz_sin(), xyz_cos().
Generalmente prefiero la función (o conjunto de funciones estrechamente relacionadas) por archivo y un archivo de encabezado por convención de archivo de origen. También es una buena idea dividir los archivos en directorios, donde cada directorio representa una biblioteca separada. En general, tendrías un sistema de makefiles o archivos de compilación que te permitirían construir todo o parte de todo el sistema siguiendo la jerarquía que representa las diversas bibliotecas/programas.
+1, pero use un único archivo Makefile que recursivamente # incluya archivos Makefile.inc en subdirectorios, ya que el archivo make recursivo tradicional puede romper sutilmente las dependencias de compilación (google "Makefiles recursivos considerados dañinos") –
Crea archivos de encabezado que contienen SOLAMENTE lo que es necesario para usar un módulo. En el (los) archivo (s) .c correspondiente, haga que todo lo que no esté destinado a ser visible fuera (por ejemplo, funciones de ayuda) estético. Use prefijos en los nombres de todo lo visible externamente para ayudar a evitar colisiones de espacios de nombres. (Si un módulo abarca múltiples archivos, las cosas se vuelven más difíciles., Ya que puede necesitar exponer cosas internas y no poder ocultarlas con "estática")
(Si tuviera que tratar de mejorar C, una cosa que haría hacer es "estático" el alcance predeterminado de las funciones. Si quisiera algo visible afuera, tendría que marcarlo con "exportar" o "global" o algo similar.)
+1. El uso de funciones estáticas para el comportamiento "privado" limita el potencial de acoplamiento innecesario. –
Asegúrese de que el encabezado funciona de forma aislada utilizándolo como el primer encabezado enumerado en el archivo de implementación. Si eso no funciona, el encabezado está incompleto. –
Pensé que static * was * el alcance predeterminado. Al menos eso es lo que recuerdo haber leído en k & r. – Breton
OO se pueden aplicar técnicas a C código, solo requieren más disciplina.
- Uso asas opacos que operan sobre los objetos. Un buen ejemplo de cómo se hace esto es la biblioteca
stdio
: todo está organizado alrededor del asa opacaFILE*
. Muchas bibliotecas exitosas se organizan en torno a este principio (por ejemplo zlib, apr) - Debido a que todos los miembros de
struct
s son implícitamentepublic
en C, se necesita una disciplina convención + programador para hacer cumplir la técnica útil de ocultación de la información. Elija una convención simple y automáticamente seleccionable como "miembros privados terminan con '_'". - Las interfaces se pueden implementar usando matrices de punteros para las funciones. Ciertamente, esto requiere más trabajo que en lenguajes como C++ que proporcionan apoyo en el lenguaje, pero sin embargo se puede hacer en C.
manijas opacas es una buena. Y aunque las estructuras son implícitamente públicas, solo si las pones en el encabezado. Puede decir, en un encabezado de usuario para una biblioteca, por ejemplo: [código] struct opaque_foo; extern int my_func (struct opaque_foo * f); [/ code] El código interno de la biblioteca, por supuesto, deletrearía lo que estaba en opaque_foo, pero no es necesario exponerlo al código que está utilizando la biblioteca. – smcameron
El enfoque que Pidgin (antes Gaim) utiliza es que crearon una estructura Plugin
. Cada complemento rellena una estructura con devoluciones de llamadas para la inicialización y el desmontaje, junto con una gran cantidad de otra información descriptiva. Prácticamente todo, excepto la estructura, se declara estática, por lo que solo se expone la estructura del complemento para el enlace.
Luego, para manejar el acoplamiento flojo del complemento que se comunica con el resto de la aplicación (ya que sería bueno si hizo algo entre la configuración y el desmontaje), tienen un sistema de señalización.Los complementos pueden registrar devoluciones de llamadas para llamar cuando se emiten señales específicas (no señales C estándar, sino un tipo extensible personalizado [identificado por cadena, en lugar de establecer códigos]) por parte de la aplicación (incluido otro complemento). También pueden emitir señales ellos mismos.
Esto parece funcionar bien en la práctica: los diferentes complementos se pueden construir unos sobre otros, pero el acoplamiento es bastante flexible, no hay invocación directa de funciones, todo se realiza a través del sistema de señalización.
+1. Esta es una forma muy extensible de diseñar un sistema. Las interfaces (tablas de devoluciones de llamada) mantienen el acoplamiento al mínimo, lo que facilita intercambiar implementaciones nuevas/mejoradas para diferentes componentes * por separado * en el futuro. –
El artículo High and Low-Level C contiene muchos buenos consejos. Especialmente, eche un vistazo a la sección "Clases y objetos".
Standards and Style for Coding in ANSI C también contiene buenos consejos que puede elegir.
+1 para los artículos! – cschol
- No definir variables en archivos de encabezado; en su lugar, defina la variable en el archivo fuente y agregue una declaración externa (declaración) en el encabezado. Esto se vinculará con los números 2 y 3.
- Utilice un protector de inclusión en cada encabezado. Esto ahorrará muchos dolores de cabeza.
- Suponiendo que ha hecho los números 1 y 2, incluya todo lo que necesita (pero solo lo que necesita) para un determinado archivo en ese archivo. No dependa del orden de cómo el compilador expande sus directivas de inclusión.
+1 para #include guardias. –
Hay un buen truco en un apéndice del libro de Andrew Glassner "Graphics Gems" en el que tiene algunas macros que le permiten definir una declaración de variable y su declaración externa (y el inicializador) en una sola línea de código en el encabezado. Esto no permite que el archivo de implementación * .c use el mismo encabezado que el código de cliente. Ejemplo de algunos de mis códigos: http://gneutronica.cvs.sourceforge.net/viewvc/gneutronica/gneutronica/midioutput_alsa.h?revision=1.3&view=markup Mire las macros GLOBAL e INIT, y cómo están condicionalmente definido. – smcameron
Una función debe hacer una cosa y hacer esto bien.
Muchas funciones pequeñas utilizadas por las funciones de envoltura más grandes ayudan a estructurar el código desde bloques de construcción pequeños, fáciles de entender (¡y probar!).
Cree pequeños módulos con un par de funciones cada uno. Solo exponga lo que debe, mantenga todo lo demás estático dentro del módulo. Enlace pequeños módulos junto con sus archivos de interfaz .h
Proporcionan funciones Getter y Setter para acceder a variables de alcance de archivos estáticos en su módulo. De esta forma, las variables solo se escriben en un solo lugar. Esto también ayuda a rastrear el acceso a estas variables estáticas utilizando un punto de interrupción en la función y la pila de llamadas.
Una regla importante al diseñar código modular es: No intente optimizar a menos que sea necesario. Muchas funciones pequeñas generalmente producen un código más limpio y bien estructurado, y la sobrecarga de llamada de función adicional puede valer la pena.
Siempre trato de mantener las variables en su ámbito más estrecho, también dentro de las funciones. Por ejemplo, los índices de bucles for usualmente pueden mantenerse en el alcance del bloque y no necesitan estar expuestos en todo el nivel de función. C no es tan flexible como C++ con "defínalo donde lo usa", pero es factible.
- 1. ¿Qué métodos existen para la llamada a procedimiento remoto local?
- 2. ¿Qué herramientas existen para probar el código .net multiproceso?
- 3. ¿Qué convenciones existen para ordenar argumentos en métodos?
- 4. ¿Qué marcos de pruebas de mutaciones existen para C/C++?
- 5. ¿Existen herramientas de combinación para el control de código fuente que entienden el código?
- 6. ¿Qué trampas existen para Django?
- 7. cómo modularizar django settings.py?
- 8. La mejor manera de modularizar un bloque de código JSP
- 9. Qué herramientas de autotest existen para Clojure
- 10. ¿Qué sucede si existen enlaces para liberar librerías de clases de "ayuda" de Excel para C#?
- 11. ¿Qué herramientas están disponibles para visualizar qué métodos llaman a otros métodos para el código de Java?
- 12. Estilo de código para métodos privados en C#
- 13. ¿Qué métodos existen para generar automáticamente stubs de clientes java a partir de archivos WSDL?
- 14. ¿Existen patrones bien conocidos para el código de red asíncrono en C#?
- 15. Herramientas para el código C refactorización
- 16. Usando el grupo de métodos C# ejecuta el código
- 17. C# Comprobar URL existen?
- 18. ¿Qué alternativas existen para WCF Test Client?
- 19. ¿Qué buenos tutoriales existen para aprender pycURL?
- 20. ¿Qué otras alternativas existen para el registro log4net?
- 21. Métodos de llamada C del código C++/Java/C#?
- 22. Analizando el código C# (como cadena) e insertando métodos adicionales
- 23. Cómo modularizar una aplicación de Python
- 24. ¿Qué alternativas a Hans Boehm GC existen para dispositivos pequeños?
- 25. ¿Qué bibliotecas JavaScript multiplataforma existen?
- 26. ¿Qué cadenas de herramientas alternativas (de trabajo) existen para el desarrollo x86 C++ en Linux?
- 27. ¿Existen directrices para cuándo se debe incluir el código reproducible en una publicación?
- 28. Qué herramientas de C# existen para desencadenar, poner en cola, priorizar tareas dependientes
- 29. Necesita comprender el siguiente código para los métodos virtuales de C#
- 30. ¿Qué herramientas XSLT 2.0 existen?
+1 Buena pregunta, estaba pensando en lo mismo esta mañana. – helpermethod