¿Cómo debo estructurar proyectos complejos en C? [closed]

8 minutos de lectura

Tengo poco más que habilidades C de nivel principiante 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, tengo miedo de estructurar mis aplicaciones de manera incorrecta. No sé qué pautas seguir para tener modularidad, desacoplamiento y sequedad con un lenguaje procedimental.

¿Tienes alguna lectura para sugerir? No pude encontrar ningún marco de aplicación para C, incluso si no uso marcos, siempre encontré buenas ideas al navegar por su código.

¿Como debo estructurar proyectos complejos en C closed
muviciel

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

  • Identifique módulos en su aplicación, como clases en una aplicación OO.
  • Interfaz e implementación separadas para cada módulo, coloque en la interfaz solo lo que necesitan otros módulos. Recuerde que no hay espacio de nombres en C, por lo que debe hacer que todo en sus interfaces sea único (por ejemplo, con un prefijo).
  • Oculte variables globales en la implementación y use funciones de acceso para lectura/escritura.
  • 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 tienes tiempo para aprender, echa un vistazo a cómo se estructura una aplicación de Ada, con su obligatorio package (interfaz del módulo) y package body (implementación del módulo).

Esto es para codificar.

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

1646760614 208 ¿Como debo estructurar proyectos complejos en C closed
j_random_hacker

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 imponer que nadie mire dentro de un struct FILEpero 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 = (struct Cat*) malloc(sizeof (struct Cat));
    x->_base.eat = cat_eat;
    x->_base.sleep = cat_sleep;
    x->meow = cat_meow;
    return x;
}

struct IAnimal* pa = CreateACat();
pa->eat(42);                       /* Calls cat_eat() */

((struct Cat*) pa)->meow();        /* "Downcast" */

  • Un codificador C puro se perdería leyendo este código…

    – Mouviciel

    19 de marzo de 2009 a las 8:06

  • @mouviciel: ¡Basura! La mayoría de los codificadores de C entienden los punteros de función (o al menos deberían), y no hay nada más allá de eso aquí. Al menos en Windows, los controladores de dispositivos y los objetos COM brindan su funcionalidad de esta manera.

    – j_random_hacker

    19 de marzo de 2009 a las 9:29

  • Mi punto no se trata de incompetencia, se trata de complicaciones innecesarias. Los punteros de función son comunes para un codificador C (por ejemplo, devoluciones de llamada), la herencia no lo es. Prefiero que un codificador de C ++ que codifica en C use su tiempo para aprender C que para construir clases de pseudo C ++. Dicho esto, su enfoque puede ser útil en algunos casos.

    – Mouviciel

    19 de marzo de 2009 a las 13:03

  • En realidad, incluso puedes simular acceder a los especificadores utilizando el modismo pimpl de C++. Si el privado los miembros de un tipo están encapsulados en un tipo que solo es visible en la implementación (también conocido como “el archivo .c”), los usuarios de la interfaz tendrán dificultades para cambiarlos (por supuesto, pueden escribir basura en el puntero del grano, si te quieren joder intencionalmentepero puede hacer lo mismo en C++).

    – máscara de bits

    14 de septiembre de 2011 a las 0:27

  • Votante negativo: ¿quieres comentar?

    – j_random_hacker

    17/10/2013 a las 16:48

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 muy derrochador.

Por ejemplo, suponga que tiene una serie 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 realizando 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 gráfico consiste en puntos y líneas, las personas construirán una estructura de datos que consistirá en objetos de puntos y objetos de líneas, cada uno capaz de DrawMyself, y luego lo harán persistente, en la teoría de que eso es de alguna manera “más eficiente”, o que tal vez, tal vez, tengan que poder pasar el mouse sobre partes del gráfico y mostrar los datos numéricamente, por lo que construyen métodos en los objetos para lidiar con eso, y eso, por supuesto, implica crear y eliminar aún más objetos.

Entonces 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 las “buenas prácticas de programación” y la “eficiencia”.

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

  • Me encanta tu respuesta, y es totalmente cierto. OOP debe morir!

    – Jo So

    18 de diciembre de 2017 a las 23:34

  • @JoSo: uso programación orientada a objetos, pero mínimamente.

    –Mike Dunlavey

    19 dic 2017 a las 21:05

  • Para mí, “mínimamente” (aunque no sé lo que eso significa para ti) realmente no cuenta como OOP, que es Object orientado programación – objetos por defecto.

    – Jo So

    19 de diciembre de 2017 a las 21:22

  • También uso algo de “OOP”. Principalmente para mis módulos C, de los cuales muchos tienen rutinas init() y exit().

    – Jo So

    19 de diciembre de 2017 a las 21:23

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 sigues al pie de la letra. Pensar en los puntos planteados en ellos le brinda una base más firme sobre cómo estructurar su 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 tiene el compilador a su lado y necesita hacer todo con mucho cuidado manualmente.

Dado que no hay paquetes ni 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, prefije 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 abstractos. 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 deben exportarse vayan al archivo de encabezado público.

Tus herramientas también son muy importantes. Una herramienta útil para C es hilas, 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.

¿Como debo estructurar proyectos complejos en C closed
Nate

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”.

1646760616 181 ¿Como debo estructurar proyectos complejos en C closed
Iván Krechetov

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad