Tengo poco más que un nivel de principiante en C y me gustaría saber si existen "estándares" de facto para estructurar una aplicación algo compleja en C. Incluso las basadas en GUI.
Siempre he estado usando el paradigma OO en Java y PHP y ahora que quiero aprender C me temo que podría estructurar mis aplicaciones de manera incorrecta. No sé qué pautas seguir para tener modularidad, desacoplamiento y sequedad con un lenguaje procedimental.
¿Tiene alguna lectura que sugerir? No pude encontrar ningún marco de aplicación para C, incluso si no uso marcos, siempre he encontrado buenas ideas al navegar por su código.
c
project-management
Stephen
fuente
fuente
Respuestas:
La clave es la modularidad. Esto es más fácil de diseñar, implementar, compilar y mantener.
Si tiene tiempo para aprender, eche un vistazo a cómo está estructurada una aplicación Ada, con su
package
(interfaz de módulo) obligatoria ypackage body
(implementación de módulo).Esto es para codificar.
Para mantener (recuerde que codifica una vez, pero mantiene varias veces) le sugiero que documente su código; Doxygen es una buena elección para mí. Sugiero también crear un conjunto de pruebas de regresión sólido, que le permita refactorizar.
fuente
Es un error común pensar que las técnicas OO no se pueden aplicar en C. La mayoría sí, es solo que son un poco más difíciles de manejar que en lenguajes con sintaxis dedicada al trabajo.
Una de las bases del diseño de un sistema robusto es la encapsulación de una implementación detrás de una interfaz.
FILE*
y las funciones que trabajan 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, dado que C carece de especificadores de acceso, no puede hacer cumplir que nadie mire dentro de astruct FILE
, pero solo un masoquista lo haría).Si es necesario, se puede tener un comportamiento polimórfico en C usando tablas de punteros 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" */
fuente
Todas buenas respuestas.
Solo agregaría "minimizar la estructura de datos". Esto podría ser incluso 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 un desperdicio.
Por ejemplo, suponga 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 la matriz haciendo funciones LineTo, escalando los datos a medida que avanza para convertirlos a coordenadas de píxeles.
Lo que he visto demasiadas veces es que, dado que el gráfico consta de puntos y líneas, la gente construirá una estructura de datos que consta de objetos puntuales y objetos de línea, cada uno capaz de DrawMyself, y luego lo hará persistente, en la teoría de que eso es de alguna manera "más eficiente", o que quizás, solo tal vez, tengan que poder pasar el mouse sobre partes del gráfico y mostrar los datos numéricamente, por lo que crean métodos en los objetos para lidiar con eso, y eso, por supuesto, implica la creación y eliminación de aún más objetos.
Así que terminas con una gran cantidad de código que es muy legible y simplemente pasa el 90% de su 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.
fuente
Los estándares de codificación GNU han evolucionado durante un par de décadas. Sería una buena idea leerlos, incluso si no los sigue al pie de la letra. Pensar en los puntos planteados en ellos le da una base más sólida sobre cómo estructurar su propio código.
fuente
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 tiene el compilador a su lado y necesita hacer todo con más cuidado manualmente.
Dado que no hay paquetes ni clases, debe comenzar diseñando 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, anteponga 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 necesitan exportarse vayan al archivo de encabezado público.
Tus herramientas también son muy importantes. Una herramienta útil para C es lint , que puede ayudarte a encontrar malos olores en tu código. Otra herramienta que puede usar es Doxygen, que puede ayudarlo a generar documentación .
fuente
La encapsulación es siempre 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".
fuente
Te sugiero que revises el código de cualquier proyecto popular en C de código abierto, como ... hmm ... kernel de Linux o Git; y mira como lo organizan.
fuente
La regla numérica para aplicaciones complejas: debe ser fácil de leer.
Para simplificar las aplicaciones complejas, utilizo Divide y vencerás .
fuente
Sugeriría leer un libro de texto de C / C ++ como primer paso. Por ejemplo, C Primer Plus es una buena referencia. Mirar los ejemplos le dará una idea de cómo mapear su Java OO a un lenguaje más procedimental como C.
fuente