programa lenguaje fuente estructuras estructura ejemplos ejecutar dev con compilar codigo c

lenguaje - Cómo estructurar un programa de C efectivamente



lenguaje c++ (7)

Primero, permítanme decir que tengo bastante experiencia en C y C ++. Sin embargo, estoy iniciando un nuevo proyecto en C y he estado trabajando en lenguajes orientados a objetos durante tanto tiempo (C # y C ++) que tengo problemas para encontrar una manera efectiva de encapsular la funcionalidad en un lenguaje de procedimiento. Mi primer pensamiento fue simplemente recurrir a mi conocimiento de OO y estructurarlo algo así como:

struct Foo { int x; char *y; }; struct Foo *new_Foo() { return (struct Foo *)malloc(sizeof(struct Foo)); } void Foo_member_function(struct Foo *foo, int z) { foo->x = z; }

Pero eso parece tedioso y contrario al espíritu de C. Sin mencionar que es el OO de un hombre pobre.

En última instancia, este programa va a ser bastante importante, por lo que comenzar con una buena organización de diseño es fundamental. Me imagino que con los años de desarrollo en C, se han desarrollado ciertos patrones de diseño para estructurar mejor el código para su mantenimiento. Al igual que la programación funcional, espero que la programación de procedimientos tenga un paradigma limpio y bastante legible.

Los punteros a artículos y libros relevantes también son aceptables.


C ha sido un lenguaje de bajo nivel y, en este sentido, sería muy útil organizar sus estructuras de datos de acuerdo con sus funciones de código y módulos.

Le sugiero que utilice typedefs y enumeraciones donde quiera que desee crear objetos de datos. Use macros o funciones estáticas para inicializar, asignar y ''destruir'' según sea necesario.


Esa es una forma bastante razonable de escribir un programa en C Hay otra aplicación grande por ahí, que hace más o menos lo mismo, llamada kernel de Linux. Algunas características casi OO usadas allí:

  • Estructuras y operaciones en estructuras para encapsulación como en su ejemplo.
  • punteros a las estructuras de base como una forma de herencia del hombre pobre: ​​encontrará un montón de referencias a la estructura kobject allí
  • Macros para generar funciones como sustituto de la programación de plantillas.

Esta es una práctica bastante normal y sensata. Pero trate de no exponer el diseño de la estructura en los archivos de encabezado, de modo que tenga cierta flexibilidad en la forma en que se implementa y administre mejor sus dependencias.

Ver puntero opaco para más detalles.


Estoy de acuerdo con las sugerencias anteriores. Lo estás haciendo de la mejor manera ... si quieres programar en C.

Por supuesto, puede escribir un preprocesador para generar automáticamente estas declaraciones y cosas para usted ... tal vez use una declaración de "Clase" ... ponga las funciones que desea que sean funciones miembro dentro de la clase ... etc.

Pero lo que tenemos aquí es un simple compilador de C ++ a C. ¿Por qué no solo programar en C ++, usar un compilador real de C ++, usar interfaces limpias y simplemente vincular el código C ++ con el código C? ¿Cuál es la razón por la que necesita codificar en C vs. C ++ de todos modos? O si lo necesita, genere el código C del compilador y compile el código C de salida junto con cualquier otra cosa que necesite.


He estado trabajando en un proyecto por un tiempo donde la biblioteca debe estar en C, pero quiero tener algún tipo de funcionalidad de OO. Estoy haciendo algo similar a esto con un poco más de detalle.

struct klass { char * value; void (*set_value) (struct klass *, const char *); void (*destroy) (struct klass *); }; static void klass_method_set_value (struct klass * k, const char * value) { if (k->value == NULL) { } } static void klass_object_desetroy (struct klass * k) { free (k); k = NULL; } static void klass_method_destroy (struct klass * k) { klass_object_destroy (k); } static struct klass * klass_object_init (void) { struct klass * obj = (struct klass *) malloc (sizeof (struct klass*) ); /* members */ obj->value = NULL; /* methods */ obj->set_value = klass_method_set_value; obj->destroy = klass_method_destroy; return obj; } struct klass * klass_new (void) { return klass_object_init (); }

Perdóname si algo está mal; Lo escribí un poco rápido.


Hmmm ... Solíamos usar convenciones de nomenclatura ... Ergo: str * hace cosas con la estructura de datos común. Así que tal vez simplemente tome la sintaxis de C # y s /./_/ g?

  • foo_constructor
  • foo_destructor
  • foo_someMethod
  • foo_someMethod2 // no hay sobrecarga en ANSI C
  • foo_otherMethod

... y no hay herencia ...

  • foo2_constructor
  • foo2_destructor
  • foo2_someMethod // y no hay polimorfismo

Pero mire el lado positivo ... ¡puede usar puntero a puntero a puntero a función-devolver-un-puntero a puntero-int! ¡Oh la alegría!

Mi mejor consejo es aprender las lecciones de Java (y por inferencia C #) y estructurar sus bibliotecas para que NO tengan efectos secundarios ... más typdefs == menos dolores de cabeza ... y si encuentra la forma de seguir este consejo sabio Por favor hagamelo saber ;-)

Aclamaciones. Keith.


Lo que estás sugiriendo es la forma en que siempre escribí programas de C en los días en que hice tal cosa. No creo que sea un "pobre hombre OO", creo que es una práctica de programación procesal sensata.

Observaría un par de cosas acerca de su código C:

  • use typedefs con definiciones de estructura para que no tenga que dispersar la palabra clave ''estructura'' en todo el código
  • solo use conversiones cuando sean realmente necesarias - la conversión en el valor de retorno de malloc () no es necesaria