Lea el SICP y aprenda el Esquema y la idea práctica de los tipos de datos abstractos . Luego, codificar en C es fácil (ya que con SICP, un poco de C y un poco de PHP, Ruby, etc., su pensamiento sería lo suficientemente amplio, y comprendería que la programación orientada a objetos podría no ser el mejor estilo en todos los casos, pero solo para algún tipo de programa). Tenga cuidado con la asignación de memoria dinámica C , que probablemente sea la parte más difícil. El estándar de lenguaje de programación C99 o C11 y su biblioteca estándar C es bastante pobre (¡no sabe sobre TCP o directorios!), Y a menudo necesitará algunas bibliotecas o interfaces externas (p. Ej.POSIX , libcurl para la biblioteca del cliente HTTP, libonion para la biblioteca del servidor HTTP, GMPlib para bignums, alguna biblioteca como libunistring para UTF-8, etc.).
Sus "objetos" a menudo están en C algunos struct
-s relacionados , y usted define el conjunto de funciones que operan en ellos. Para funciones cortas o muy simples, considere definirlas, con la correspondiente struct
, como static inline
en algún archivo de encabezado foo.h
para ser #include
-d en otro lugar.
Tenga en cuenta que la programación orientada a objetos no es el único paradigma de programación . En algunas ocasiones, otros paradigmas valen la pena ( programación funcional a la Ocaml o Haskell o incluso Scheme o Commmon Lisp, programación lógica a la Prolog, etc. etc ... Lea también el blog de J.Pitrat sobre inteligencia artificial declarativa). Ver el libro de Scott: Pragmática del lenguaje de programación
En realidad, un programador en C, o en Ocaml, generalmente no quiere codificar en un estilo de programación orientado a objetos. No hay razón para obligarse a pensar en objetos cuando eso no es útil.
Definirá algunos struct
y las funciones que operan en ellos (a menudo a través de punteros). Es posible que necesite algunas uniones etiquetadas (a menudo, struct
con un miembro de etiqueta, a menudo algunas enum
y algunas union
dentro), y puede resultarle útil tener un miembro de matriz flexible al final de algunos de sus struct
-s.
Mire dentro del código fuente de algún software libre existente en C (vea github & sourceforge
para encontrar algunos). Probablemente, instalar y usar una distribución de Linux sería útil: está hecho casi exclusivamente de software libre, tiene excelentes compiladores de software libre C ( GCC , Clang / LLVM ) y herramientas de desarrollo. Consulte también Programación avanzada de Linux si desea desarrollar para Linux.
No olvide compilar todas las advertencias e información de depuración, por ejemplo, gcc -Wall -Wextra -g
notablemente durante las fases de desarrollo y depuración, y aprenda a usar algunas herramientas, por ejemplo, valgrind para buscar fugas de memoria , el gdb
depurador, etc. Tenga cuidado de comprender bien lo que no está definido. comportamiento y evítelo (recuerde que un programa podría tener algo de UB y que a veces parece "funcionar").
Cuando realmente necesita construcciones orientadas a objetos (en particular herencia ) puede usar punteros a estructuras relacionadas y funciones. Puede tener su propia maquinaria vtable , hacer que cada "objeto" comience con un puntero a una struct
función que contiene punteros. Aprovecha la capacidad de emitir un tipo de puntero a otro tipo de puntero (y el hecho de que puede emitir desde un que struct super_st
contenga los mismos tipos de campo que aquellos que comienzan struct sub_st
a emular la herencia). Tenga en cuenta que C es suficiente para implementar sistemas de objetos bastante sofisticados, en particular siguiendo algunas convenciones , como lo demuestra GObject (de GTK / Gnome).
Cuando realmente necesite cierres , a menudo los emulará con devoluciones de llamada , con la convención de que cada función que utiliza una devolución de llamada pasa tanto un puntero de función como algunos datos del cliente (consumidos por el puntero de función cuando llama a eso). También podría tener (convencionalmente) sus propios cierres como struct
(que contienen algún puntero de función y los valores cerrados).
Dado que C es un lenguaje de muy bajo nivel, es importante definir y documentar sus propias convenciones (inspiradas en la práctica en otros programas de C), en particular sobre la administración de memoria, y probablemente también algunas convenciones de nomenclatura. Es útil tener alguna idea sobre la arquitectura del conjunto de instrucciones . No olvide que un compilador de C puede hacer muchas optimizaciones en su código (si lo solicita), así que no se preocupe demasiado por hacer micro-optimizaciones a mano, déjelo a su compilador ( gcc -Wall -O2
para una compilación optimizada de software). Si le interesan las evaluaciones comparativas y el rendimiento sin procesar, debe habilitar las optimizaciones (una vez que se haya depurado el programa).
No olvides que a veces la metaprogramación es útil . Muy a menudo, el software grande escrito en C contiene algunos scripts o programas ad-hoc para generar algún código C utilizado en otro lugar (y también puede jugar algunos trucos sucios del preprocesador C , por ejemplo , macros X ). Existen algunos generadores de programas C útiles (por ejemplo, yacc o gnu bison para generar analizadores, gperf para generar funciones hash perfectas, etc.). En algunos sistemas (especialmente Linux y POSIX), incluso podría generar algún código C en tiempo de ejecución en el generated-001.c
archivo, compilarlo en un objeto compartido ejecutando algún comando (como gcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so
) en tiempo de ejecución, cargar dinámicamente ese objeto compartido usando dlopen& obtener un puntero de función de un nombre usando dlsym . Estoy haciendo tales trucos en MELT (un lenguaje específico de dominio similar a Lisp que podría serle útil, ya que permite la personalización del compilador GCC ).
Tenga en cuenta los conceptos y técnicas de recolección de basura (el conteo de referencias es a menudo una técnica para administrar la memoria en C, y en mi humilde opinión, es una forma pobre de recolección de basura que no trata bien con referencias circulares ; podría tener punteros débiles para ayudar con eso, pero puede ser complicado) En algunas ocasiones, puede considerar usar el recolector de basura conservador de Boehm .
qux = foo.bar(baz)
vuelvenqux = Foo_bar(foo, baz)
.