Lisez SICP et découvrez Scheme, ainsi que l’ idée pratique des types de données abstraits . Il est alors facile de coder en C (car avec SICP, un peu de C, et un peu de PHP, Ruby, etc ...), votre réflexion serait suffisamment élargie et vous comprendriez que la programmation orientée objet peut ne pas être le meilleur style en tous les cas, mais seulement pour certains types de programmes). Faites attention à l'allocation de mémoire dynamique en C , qui est probablement la partie la plus difficile. Le langage de programmation standard C99 ou C11 et sa bibliothèque standard C sont en fait assez médiocres (on ne connaît pas le protocole TCP ni les répertoires!), Et vous aurez souvent besoin de bibliothèques externes ou d’interfaces (par exemplePOSIX , libcurl pour la bibliothèque client HTTP, libonion pour la bibliothèque de serveur HTTP, GMPlib pour les fichiers bignums, une bibliothèque comme libunistring pour UTF-8, etc ...).
Vos "objets" sont souvent en C, des struct
-s liés , et vous définissez l’ensemble des fonctions qui les exploitent. Pour des fonctions courtes ou très simples, pensez à les définir, avec les éléments pertinents struct
, comme static inline
dans certains fichiers d’en-tête qui foo.h
doivent être #include
-d ailleurs.
Notez que la programmation orientée objet n'est pas le seul paradigme de programmation . Dans certains cas, d'autres paradigmes sont intéressants ( programmation fonctionnelle à la Ocaml ou Haskell ou encore Scheme ou Commmon Lisp, programmation logique à la Prolog, etc. etc ... Lisez également le blog de J.Pitrat sur l'intelligence artificielle déclarative). Voir le livre de Scott: Programming Language Pragmatique
En réalité, un programmeur en C ou en Ocaml ne souhaite généralement pas coder dans un style de programmation orienté objet. Il n'y a aucune raison de vous forcer à penser à des objets quand cela ne sert à rien.
Vous en définirez certaines struct
et leurs fonctions (souvent par le biais de pointeurs). Vous pourriez avoir besoin de quelques unions étiquetées (souvent, un struct
membre avec un tag, souvent enum
, et d’autres à l’ union
intérieur), et il pourrait être utile d’avoir un membre de tableau flexible à la fin de certains de vos struct
-s.
Regardez à l'intérieur du code source de certains logiciels libres existants en C (voir github & sourceforge
pour en trouver). Il est probablement utile d’installer et d’utiliser une distribution Linux: celle-ci n’est constituée que de logiciels libres, elle dispose d’excellents compilateurs de logiciels libres ( GCC , Clang / LLVM ) et d’outils de développement. Voir aussi Programmation Linux avancée si vous souhaitez développer pour Linux.
N'oubliez pas de compiler avec tous les avertissements et informations de débogage, par exemple, gcc -Wall -Wextra -g
notamment pendant les phases de développement et de débogage, et d'apprendre à utiliser certains outils, par exemple, valgrind pour chasser les fuites de mémoire , le gdb
débogueur, etc. Veillez à bien comprendre ce qui n'est pas défini comportement et évitez-le fortement (rappelez-vous qu'un programme peut avoir un UB et parfois sembler "fonctionner").
Lorsque vous avez réellement besoin de constructions orientées objet (notamment l' héritage ), vous pouvez utiliser des pointeurs sur des structures et des fonctions associées. Vous pouvez avoir votre propre machine vtable , chaque objet commençant par un pointeur sur un struct
pointeur de fonction contenant. Vous tirez parti de la possibilité de convertir un type de pointeur en un autre type de pointeur (et du fait que vous pouvez convertir à partir d'un struct super_st
contenant les mêmes types de champs que ceux commençant par struct sub_st
émuler un héritage). Notez que C est suffisant pour implémenter des systèmes d’objets assez sophistiqués - en particulier en respectant certaines conventions -, comme le montre GObject (de GTK / Gnome).
Lorsque vous avez réellement besoin de fermetures , vous les imitez souvent avec des rappels , avec la convention selon laquelle chaque fonction utilisant un rappel est transmise à la fois à un pointeur de fonction et à certaines données client (utilisées par le pointeur de la fonction lorsqu'il appelle cela). Vous pourriez aussi avoir (de manière conventionnelle) vos propres struct
-s de type fermeture (contenant un pointeur de fonction et les valeurs fermées).
Comme le langage C est un langage de très bas niveau, il est important de définir et de documenter vos propres conventions (inspirées de la pratique des autres programmes C), en particulier en ce qui concerne la gestion de la mémoire, et probablement aussi certaines conventions de dénomination. Il est utile d’avoir une idée de l’ architecture des jeux d’instructions . Ne pas oublier que un C compilateur peut faire beaucoup d' optimisations sur votre code (si vous lui demandez), il ne se soucie pas trop de faire des micro-optimisations à la main, que l' autorisation à votre compilateur ( gcc -Wall -O2
pour la compilation optimisée de sortie Logiciel). Si vous vous souciez de l'analyse comparative et des performances brutes, vous devez activer les optimisations (une fois que votre programme a été débogué).
N'oubliez pas que parfois, la métaprogrammation est utile . Assez souvent, les gros logiciels écrits en C contiennent des scripts ou des programmes ad-hoc pour générer du code C utilisé ailleurs (et vous pouvez également jouer à des astuces de préprocesseur sales , par exemple X-macros ). Il existe des générateurs de programmes C utiles (par exemple, yacc ou gnu bison pour générer des analyseurs syntaxiques, gperf pour générer des fonctions de hachage parfait, etc.). Sur certains systèmes (notamment Linux et POSIX), vous pouvez même générer du code C à l'exécution generated-001.c
, le compiler en un objet partagé en exécutant une commande (comme gcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so
) à l'exécution, charger cet objet partagé de manière dynamique à l'aide de dlopen.& récupère un pointeur de fonction à partir d’un nom utilisant dlsym . Je fais de telles astuces dans MELT (un langage spécifique au domaine, similaire à Lisp, qui pourrait vous être utile, car il permet la personnalisation du compilateur GCC ).
Soyez conscient des concepts et des techniques de collecte des déchets (le comptage de références est souvent une technique de gestion de la mémoire en C, et IMHO est une forme de collecte des déchets médiocre qui ne traite pas bien les références circulaires ; vous pourriez avoir des pointeurs faibles pour vous aider, mais cela peut être délicat). À certaines occasions, vous pourriez envisager d'utiliser le récupérateur de déchets conservateur de Boehm .
qux = foo.bar(baz)
deviennentqux = Foo_bar(foo, baz)
.