c project-management

¿Cómo debería estructurar proyectos complejos en C?



project-management (9)

Es un concepto erróneo común que las técnicas OO no se pueden aplicar en C. La mayoría puede, es solo que son un poco más difíciles de manejar que en los lenguajes con sintaxis dedicada al trabajo.

Una de las bases del diseño sólido del sistema es la encapsulación de una implementación detrás de una interfaz. FILE* y las funciones que funcionan con él ( fopen() , fread() etc.) es un buen ejemplo de cómo se puede aplicar la encapsulación en C para establecer interfaces. (Por supuesto, como C carece de especificadores de acceso, no se puede forzar que nadie mire dentro de un struct FILE , pero solo un masoquista lo haría).

Si es necesario, se puede tener un comportamiento polimórfico en C usando tablas de indicadores de función. Sí, la sintaxis es fea pero el efecto es el mismo que el de las funciones virtuales:

struct IAnimal { int (*eat)(int food); int (*sleep)(int secs); }; /* "Subclass"/"implement" IAnimal, relying on C''s guaranteed equivalence * of memory layouts */ struct Cat { struct IAnimal _base; int (*meow)(void); }; int cat_eat(int food) { ... } int cat_sleep(int secs) { ... } int cat_meow(void) { ... } /* "Constructor" */ struct Cat* CreateACat(void) { struct Cat* x = (Cat*) malloc(sizeof (struct Cat)); x->_base.eat = cat_eat; x->_base.sleep = cat_sleep; x->meow = cat_meow; } struct IAnimal* pa = CreateACat(); pa->eat(42); /* Calls cat_eat() */ ((struct Cat*) pa)->meow(); /* "Downcast" */

Tengo poco más que habilidades de nivel principiante C y me gustaría saber si hay algún "estándar" de facto para estructurar una aplicación algo compleja en C. Incluso las basadas en GUI.

Siempre he estado usando el paradigma de OO en Java y PHP y ahora que quiero aprender C. Me temo que podría estructurar mis aplicaciones de la manera incorrecta. No sé qué pautas seguir para modularidad, desacoplamiento y sequedad con un lenguaje de procedimiento.

¿Tiene alguna lectura que sugerir? No pude encontrar ningún marco de aplicación para C, incluso si no uso frameworks, siempre encontré buenas ideas navegando en su código.


La clave es la modularidad. Esto es más fácil de diseñar, implementar, compilar y mantener.

  • Identifica módulos en tu aplicación, como clases en una aplicación OO.
  • Interfaz e implementación separadas para cada módulo, poner en interfaz solo lo que necesitan otros módulos. Recuerde que no hay espacio de nombre en C, por lo que debe hacer que todo en sus interfaces sea único (por ejemplo, con un prefijo).
  • Ocultar variables globales en la implementación y usar funciones de acceso para leer / escribir.
  • No pienses en términos de herencia, sino en términos de composición. Como regla general, no intente imitar C ++ en C, esto sería muy difícil de leer y mantener.

Si tiene tiempo para aprender, eche un vistazo a cómo se estructura una aplicación Ada, con su package obligatorio (interfaz de módulo) y el package body (implementación del módulo).

Esto es para codificar

Para mantener (recuerde que codifica una vez, pero la mantiene varias veces), sugiero que documente su código; Doxygen es una buena opción para mí. También sugiero construir un conjunto de pruebas de regresión fuerte, que le permita refactorizar.


La encapsulación siempre es clave para un desarrollo exitoso, independientemente del lenguaje de desarrollo.

Un truco que he usado para ayudar a encapsular métodos "privados" en C es no incluir sus prototipos en el archivo ".h".


La regla numérica para aplicaciones complejas: debe ser fácil de leer.

Para simplier la aplicación compleja, empleo Divide y conquista .


Los estándares de codificación GNU han evolucionado en un par de décadas. Sería una buena idea leerlos, incluso si no los sigues al pie de la letra. Pensando en los puntos planteados en ellos te da una base más firme sobre cómo estructurar tu propio código.


Si sabe cómo estructurar su código en Java o C ++, puede seguir los mismos principios con el código C. La única diferencia es que no tienes el compilador a tu lado y tienes que hacer todo extra cuidadosamente de forma manual.

Como no hay paquetes y clases, debe comenzar por diseñar cuidadosamente sus módulos. El enfoque más común es crear una carpeta de origen separada para cada módulo. Debe confiar en las convenciones de nomenclatura para diferenciar el código entre diferentes módulos. Por ejemplo, prefija todas las funciones con el nombre del módulo.

No puede tener clases con C, pero puede implementar fácilmente "Tipos de datos abstractos". Crea un archivo .C y .H para cada tipo de datos abstracto. Si lo prefiere, puede tener dos archivos de encabezado, uno público y otro privado. La idea es que todas las estructuras, constantes y funciones que se deben exportar vayan al archivo de encabezado público.

Tus herramientas también son muy importantes. Una herramienta útil para C es la lint , que puede ayudarlo a encontrar malos olores en su código. Otra herramienta que puede usar es Doxygen, que puede ayudarlo a generar Doxygen .


Sugiero leer un libro de texto C / C ++ como primer paso. Por ejemplo, C Primer Plus es una buena referencia. Si examina los ejemplos, obtendrá una idea sobre cómo asignar su OO de Java a un lenguaje más procesal, como C.


Te sugiero que revises el código de cualquier proyecto C de código abierto popular, como ... hmm ... Linux kernel, o Git; y mira cómo lo organizan.


Todas las buenas respuestas.

Solo agregaría "minimizar estructura de datos". Esto podría ser aún más fácil en C, porque si C ++ es "C con clases", OOP está tratando de alentarlo a tomar cada sustantivo / verbo en su cabeza y convertirlo en una clase / método. Eso puede ser muy derrochador.

Por ejemplo, supongamos que tiene una matriz de lecturas de temperatura en puntos en el tiempo, y desea mostrarlas como un gráfico de líneas en Windows. Windows tiene un mensaje PAINT, y cuando lo recibe, puede recorrer el conjunto haciendo funciones LineTo, escalando los datos a medida que avanza para convertirlos en coordenadas de píxeles.

Lo que he visto demasiadas veces es que, dado que el cuadro consta de puntos y líneas, las personas construirán una estructura de datos que constará de objetos puntuales y objetos de línea, cada uno capaz de dibujar yo mismo, y luego lo mantendrán persistente, en la teoría de que de alguna manera es "más eficiente", o que quizás, tal vez, tengan que poder pasar el ratón sobre partes del gráfico y mostrar los datos numéricamente, de modo que construyan métodos en los objetos para manejar eso, y eso, por supuesto, implica crear y eliminar aún más objetos.

Así que terminas con una gran cantidad de código que es muy legible y simplemente gasta el 90% del tiempo administrando objetos.

Todo esto se hace en nombre de "buenas prácticas de programación" y "eficiencia".

Al menos en C, la forma simple y eficiente será más obvia, y la tentación de construir pirámides será menos fuerte.