commit 6ead1ec36508dca5d65cd50207021519b937fc28
parent cf07cc9eb56cda8bb4a12ec0245908082ff8ea49
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 14 Oct 2026 17:22:58 +0200
Rédige la section "fichiers"
Ajoute un fichier vimrc documenté dans la page de manuel. Le chemin vers
ce fichier dépend de son répertoire d'installation. Par conséquent, le
man, qui y fait référence, devient générique à ce répertoire et dois
donc être régénéré à chaque invocation du make.
Diffstat:
| M | .gitignore | | | 1 | + |
| M | Makefile | | | 25 | +++++++++++++++++++++---- |
| M | config.mk | | | 1 | + |
| D | doc/fr/star-c.7 | | | 1792 | ------------------------------------------------------------------------------- |
| A | doc/fr/star-c.7.in | | | 1804 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | vimrc | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
6 files changed, 1918 insertions(+), 1796 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,2 +1,3 @@
*~
*.swp
+star-c.7
diff --git a/Makefile b/Makefile
@@ -19,15 +19,32 @@
include config.mk
-default:
+MAN = doc/fr/star-c.7
-lint:
- mandoc -Tlint -Werror doc/fr/star-c.7
+default: $(MAN)
-install:
+man: # Force rebuild
+
+doc/fr/star-c.7: man
+ sed 's#@APPPREFIX@#$(APPPREFIX)#g' $@.in > $@
+
+clean:
+ rm -f $(MAN)
+
+lint: $(MAN)
+ @for i in $(MAN); do \
+ printf 'lint %s\n' "$${i}"; \
+ mandoc -Tlint -Werror "$${i}"; \
+ done
+
+install: $(MAN)
mkdir -p "$(DESTDIR)$(MANPREFIX)/fr/man7"
cp doc/fr/star-c.7 "$(DESTDIR)$(MANPREFIX)/fr/man7"
chmod 644 "$(DESTDIR)$(MANPREFIX)/fr/man7/star-c.7"
+ mkdir -p "$(DESTDIR)$(APPPREFIX)/star-style"
+ cp vimrc "$(DESTDIR)$(APPPREFIX)/star-style"
+ chmod 644 "$(DESTDIR)$(APPPREFIX)/star-style/vimrc"
uninstall:
rm -rf "$(DESTDIR)$(MANPREFIX)/fr/man7/star-c.7"
+ rm -rf "$(DESTDIR)$(APPPREFIX)/star-style/vimrc"
diff --git a/config.mk b/config.mk
@@ -1,3 +1,4 @@
# Default install paths
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
+APPPREFIX = $(PREFIX)/share
diff --git a/doc/fr/star-c.7 b/doc/fr/star-c.7
@@ -1,1792 +0,0 @@
-.\" Copyright (C) 2026 |Méso|Star> (contact@meso-star.com)
-.\"
-.\" Ce fichier fait partie de Star-Style.
-.\"
-.\" Star-Style est un logiciel libre ; vous pouvez le redistribuer ou le
-.\" modifier suivant les termes de la GNU General Public License telle
-.\" que publiée par la Free Software Foundation ; soit la version 3 de
-.\" la licence, soit (à votre gré) toute version ultérieure.
-.\"
-.\" Star-Style est distribué dans l'espoir qu'il sera utile, mais SANS
-.\" AUCUNE GARANTIE ; sans même la garantie tacite de QUALITÉ MARCHANDE
-.\" ou d'ADÉQUATION à UN BUT PARTICULIER. Consultez la GNU General
-.\" Public License pour plus de détails.
-.\"
-.\" Vous devez avoir reçu une copie de la GNU General Public License en
-.\" même temps que Star-Style ; si ce n'est pas le cas, consultez
-.\" <http://www.gnu.org/licenses>.
-.Dd October 14, 2026
-.Dt STAR-C 7
-.Os
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh NOM
-.Nm star-c
-.Nd guide d'écriture de code en C
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh DESCRIPTION
-Ce document décrit les conventions d'écriture des programmes C
-distribués par |Méso|Star>.
-Ces recommandations sont données à titre indicatif, et reste
-subordonnées aux pratiques effectivement retenues dans chaque
-projet ; le plus important étant d'en conserver la cohérence.
-Si bien que s'il appartient aux co-auteurs d'un projet de prendre
-certaines libertés quant à ce guide de style, toute participation à son
-développement devra alors s'efforcer de respecter le style d'écriture du
-projet, avant les préférences listées ici.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LE CONTENU D'UN PROJET
-En suivant le philosophie UNIX, assurer un jeu de
-fonctionnalités par programme aussi ramassé que possible de
-sorte à ce que sa mise en oeuvre et son interface restent
-simples et ciselées.
-L'objet étant d'assurer sa robustesse, son efficacité et sa
-modularité qui dépendent d'abord de sa
-.Em relation
-à un écosystème logiciel qui le dépasse, bien avant son catalogue de
-fonctionnalités ou ses prouesses de mise en oeuvre.
-.Pp
-Le périmètre étroit de chaque programme se retrouve dès lors dans la
-structure du projet auquel il appartient, dont le contenu est alors
-simple et peu hiérarchisé car comptant en définitive peu de fichiers.
-.Pp
-La structure type du répertoire d'un projet est :
-.Bd -literal -offset Ds
-README.md
-COPYING
-config.mk
-Makefile
-src/foo.h
-src/foo.c
-src/foo_bar.c
-doc/foo_bar.1
-doc/foo.3
-.Ed
-.Pp
-Avec :
-.Bl -dash -compact
-.It
-.Pa README.md
-le fichier qui donne le premier niveau d'informations sur le projet ;
-.It
-.Pa COPYING
-la license du projet qui liste ses conditions légales d'utilisation ;
-.It
-.Pa config.mk
-et
-.Pa Makefile
-les fichiers du système de génération automatique du projet ;
-.It
-.Pa src/
-le répertoire qui contient les codes source du projet ;
-.It
-.Pa doc/
-le répertoire qui stocke sa documentation.
-.El
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LE LANGAGE C
-Utiliser le langage
-.Em C89
-.Pq ANSI X3.159-1989
-aussi appelé C90
-.Pq ISO/IEC 9899:1990 ,
-les deux étant équivalent.
-.Pp
-Cette norme est plus épurée que celle qui lui succède à savoir le C99
-.Pq ISO SO/IEC 9899:1999 ,
-ce qui en fait un dialecte C à la fois plus simple, plus portable et
-plus consistant.
-Par exemple en ne proposant qu'une seule façon d'écrire les commentaires,
-et en interdisant de mélanger du code avec la définition de variables.
-.\""""""""""""""""""""""""""""""""""
-.Ss Le standard POSIX
-Ajouter le support du standard POSIX pour les seuls fichiers qui en ont
-besoin, pour notamment pouvoir utiliser des fonctions de la bibliothèque
-C standard sinon indisponibles via la seule norme du langage retenue.
-.Pp
-Pour ce faire, définir la macro
-.Sy _POSIX_C_SOURCE
-tout en haut du fichier C concerné, avant la moindre directive
-d'inclusion.
-Par exemple, pour utiliser le standard POSIX.1-2001 :
-.Bd -literal -offset Ds
-#define _POSIX_C_SOURCE 200112L
-.Ed
-.Pp
-Sous GNU/Linux, se référer à
-.Xr feature_test_macros 7
-pour une description exhaustive des macros utilisées pour activer le jeu
-de fonctionnalités d'un standard donné.
-.Pp
-L'utilisation d'un C enrichi du standard POSIX n'est ainsi utilisé que
-sur les seuls fichiers qui en explicite le besoin ; le C89 restant le
-langage utilisé partout ailleurs.
-Dans un même souci de portabilité, retenir la première version du
-standard POSIX à partir de laquelle la fonctionnalité recherchée est
-apparue.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LA STRUCTURE D'UN FICHIER SOURCE
-Suivre une seule et même structure pour tous les fichiers
-sources, qu'ils soient des fichiers d'en-tête
-.Pq fichiers Ql *.h
-ou des unités de compilation
-.Pq fichiers Ql *.c .
-Un seul schéma de lecture participant à la clarté du code source.
-.Pp
-Ci-après sont listées les différentes parties d'un fichier source :
-.Bl -enum
-.\""""""""""""""""""""""""""""""""""
-.It
-Un commentaire avec l'avis de copyright et les avis de licence du
-programme
-.Pq section Sx L'AVIS DE COPYRIGHT ET LES AVIS DE LICENCE Ns
- ;
-.\""""""""""""""""""""""""""""""""""
-.It
-La définition des macros qui ajoute au langage C du fichier le support
-d'un standard POSIX
-.Pq section Sx LE LANGAGE C Ns
- ;
-.\""""""""""""""""""""""""""""""""""
-.It
-Pour un fichier d'en-tête, l'ouverture d'un garde-fou évitant sa double
-inclusion.
-Il est fermé en toute fin du fichier
-.Pq partie 10 Ns
- :
-.Bd -literal -offset Ds
-#ifndef FOO_H
-#define FOO_H
-.Ed
-.Pp
-Le nom de la macro testée puis définie est celui du fichier d'en-tête,
-en majuscule, suffixé par
-.Ql _H
-en référence à l'extension
-.Ql .h
-du fichier.
-Dans l'exemple qui précède, le garde-fou concerne donc le fichier
-.In foo.h .
-La convention de nommage est sinon celle utilisée pour n'importe quelle
-macro
-.Pq section Sx LE NOMMAGE .
-.\""""""""""""""""""""""""""""""""""
-.It
-L'inclusion des fichiers d'en-tête requis par le fichier source ;
-.Pq section Sx LES FICHIERS D'EN-TÊTE Ns
- ;
-.\""""""""""""""""""""""""""""""""""
-.It
-La définition des macros
-.Pq section Sx LES MACROS Ns
- ;
-.\""""""""""""""""""""""""""""""""""
-.It
-La déclaration anticipée des types structurés :
-.Bd -literal -offset Ds
-/* Type structurés externes au programme */
-struct plugh;
-struct quux;
-struct xyzzy;
-
-/* Types structurés définis ailleurs dans le programme */
-struct bar;
-struct foo;
-.Ed
-.\""""""""""""""""""""""""""""""""""
-.It
-La définition des constantes symboliques de type
-.Vt enum
-.Pq section Sx LES CONSTANTES SYMBOLIQUES Ns
- ;
-.\""""""""""""""""""""""""""""""""""
-.It
-La définition des types structurés et de leur(s) constante(s)
-.Pq section Sx LES STRUCTURES Ns
- ;
-.\""""""""""""""""""""""""""""""""""
-.It
-La déclaration et définition des fonctions
-.Pq section Sx LES FONCTIONS .
-Dans l'ordre qui suit :
-.Pp
-.Bl -tag -compact -width a.
-.It a.
-la déclaration des fonctions ;
-.It b.
-la définition des fonctions statiques ;
-.It c.
-pour les unités de compilation, la définition des fonctions.
-.El
-.\""""""""""""""""""""""""""""""""""
-.It
-Pour les fichiers d'en-tête, la fin du garde-fou ouvert en 3 pour éviter
-la double inclusion du contenu du fichier.
-.El
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LA LONGUEUR DES LIGNES
-La longueur maximale recommandée pour une ligne est de
-.Em 80
-caractères.
-.Pp
-Ce nombre, standardisé par les cartes perforées et les terminaux des
-années 1970, vise aussi à faciliter la lecture du code source en
-s'insipirant des conventions d'édition.
-Pour un texte imprimé avec une taille de police entre 9 à 12 points et
-un inter-ligne d'un caractère, un confort de lecture est assuré dès
-lors que chaque ligne compte entre 60 et 75 caractères.
-Une proximité avec les 80 caractères retenus, que l'indentation
-des sources vient encore renforcer.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh L'AVIS DE COPYRIGHT ET LES AVIS DE LICENCE
-Utiliser la licence libre GPLv3+ qui, en tant que licence copyleft,
-défend la copie, l'étude et la modification libres du programme ainsi
-licencié, et de ses évolutions.
-.Pp
-Ajouter une copie de la licence à la racine du projet, dans un fichier
-texte nommé
-.Pa COPYING
-.Pq voir Lk https://www.gnu.org/licenses/gpl-3.0.txt .
-.Pp
-Lister en commentaire l'avis de copyright et la déclaration
-d'autorisation de copie en en-tête de
-.Em chaque
-fichier source.
-.Pp
-Chaque copyright débute par le mot
-.Ql Copyright ,
-en anglais, suivi des 3 caractères
-.Ql (C) ,
-traduction ASCII du caractère © qui, quant à lui, peut ne pas être
-supporté par la police de caractères utilisée.
-Lister ensuite les années pour lesquelles une version du programme a été
-publiée, avant le nom de l'auteur(e) ayant participé(e) à
-sa réalisation.
-Conclure chaque avis par l'adresse de contact de l'auteur(e), donnée
-entre parenthèses.
-.Pp
-Sauter une ligne après l'avis de copyright et ajouter la déclaration
-autorisant la copie telle que donnée par la Fondation pour le logiciel
-libre.
-Utiliser l'avis de copyright en anglais qui, au contraire de sa
-traduction française, revêt une signification juridique.
-.Pp
-L'en-tête type d'un fichier source du programme
-.Ql Foo
-est :
-.Bd -literal -offset Ds
-/* Copyright (C) 2016-2018, 2020, 2022, 2026
- * Jeanne Lambda (jeanne.lambda@courriel.fr)
- * Copyright (C) 2017, 2019 Jean Untel (juntel@courriel.fr)
- * Copyright (C) 2024 |Méso|Star> (contact@meso-star.com)
- *
- * This file is part of Foo.
- *
- * Foo is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later
- * version.
- *
- * Foo is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with Foo. If not, see
- * <https://www.gnu.org/licenses/>. */
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh L'INDENTATION
-Indenter le texte par 2 espaces.
-La mise en page du texte, taille de ligne comprise, est ce faisant
-indépendante de la taille d'une tabulation.
-.Pp
-Les auteures et auteurs sont encouragés à configurer leur éditeur de
-texture pour qu'il développe chaque caractère tabulation en 2 espaces
-.Pq section Sx FICHIERS .
-Et ainsi continuer à utiliser la touche tabulation pour l'indentation.
-.Pp
-Limiter l'indentation à 2 caractères, contre 8 pour le standard de facto
-des tabulations, laisse plus d'espace aux différents niveaux
-d'indentation, dès lors moins contraints par la limite du nombre de
-caractères par ligne
-.Pq section Sx LA LONGUEUR DES LIGNES .
-Néanmoins, un niveau d'indentation supérieur à 3 est aussi le signe d'un
-déficit de structure dans l'écriture du programme.
-Les 2 espaces retenus pour indenter le code n'est donc pas une
-incitation à aller au delà de 3 niveaux d'indentation sous prétexte de
-disposer de plus d'espace par niveau.
-.Pp
-Indenter le contenu de chaque bloc
-.Pq section Sx LES BLOCS .
-Pour la directive
-.Ql switch ,
-indenter chaque
-.Ql case
-ainsi que leur contenu :
-.Bd -literal -offset Ds
-switch (opt) {
- case 'e':
- errno = 0;
- epsilon = strtod(optarg, NULL);
- if (errno != 0) err = 1;
- break;
- case 'h':
- printf("usage: foo [-hov]\en");
- break;
- case 'o':
- output = optarg;
- break;
- case 'v':
- verbose += (verbose < 3);
- break;
- default:
- err = 1;
- break;
-}
-.Ed
-.Pp
-Motiver l'utilisation de plusieurs instructions par ligne par
-l'expressivité du code en résultant, qu'une écriture resserrée viendrait
-renforcer :
-.Bd -literal -offset Ds
-if (x == NULL || y == NULL) { err = 1; goto error; }
-x[0] = 1.0; x[1] = 0.0;
-y[0] = 0.0; y[1] = 1.0;
-.Ed
-.Pp
-Ne sauter au plus qu'une ligne.
-Ne pas laisser d'espace en fin de ligne et supprimer les lignes vides
-en fin de fichier.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES COMMENTAIRES
-Utiliser des commentaires dès lors que la seule expressivité serrée du
-code ne permet pas d'exprimer l'entièreté du discours que les sources
-doivent rendre compte, ou la logique qu'il met effectivement en oeuvre.
-.Pp
-Ajouter un espace après l'ouverture du commentaire
-.Ql /*
-et avant sa fermeture
-.Ql */ .
-.Pp
-Si un commentaire occupe plusieurs lignes, ajouter un caractère
-.Ql *
-en début de ligne, aligné avec le caractère
-.Ql *
-de la ligne qui précède.
-Ajouter un espace entre le caractère
-.Ql * ,
-qui marque la continuation du commentaire, et la suite du commentaire :
-.Bd -literal -offset Ds
-/* Valeurs de hachage initiales, à savoir les 32 premiers bits
- * de la partie fractionnaire des racines carrées des 4 premiers
- * nombres premiers (2, 3, 5 et 7) */
-state[0] = 0x6a09e667;
-state[1] = 0xbb67ae85;
-state[2] = 0x3c6ef372;
-state[3] = 0xa54ff53a;
-.Ed
-.Pp
-Les commentaires servent aussi à structurer la lecture du code source.
-Que ce soit à l'échelle des instructions, par un commentaire
-.Dq chapeau
-qui résume la séquence de code qui suit :
-.Bd -literal -offset Ds
-/* Enregistrer le résultat */
-((uint32_t*)hash)[0] = big_endian_32(state[0]);
-((uint32_t*)hash)[1] = big_endian_32(state[1]);
-((uint32_t*)hash)[2] = big_endian_32(state[2]);
-((uint32_t*)hash)[3] = big_endian_32(state[3]);
-.Ed
-.Pp
-ou à l'échelle du fichier, où les commentaires servent alors de
-séparateur entre ses différentes sections
-.Pq voir Sx LA STRUCTURE D'UN FICHIER SOURCE .
-Dans ce cas, encadrer le commentaire par deux ligne de caractères
-.Ql *
-qui débute ou se termine par le caractère
-.Ql /
-si, respectivement, la ligne précède ou suit l'intitulé de la section :
-.Bd -literal -offset Ds
-/***********************************************************
- * Définition des fonctions utilitaires
- **********************************************************/
-static void
-foo(uint32_t bar[4], const char baz[64])
-{
- ...
-}
-
-static int
-qux(const int xyzzy)
-{
- ...
-}
-.Ed
-.Pp
-À noter que dans l'exemple qui précède, la taille des lignes
-d'encadrement est limitée par des contraintes d'édition de la présente
-page de manuel.
-Dans un fichier source, étendre ces lignes pour qu'elles occupent la
-longueur maximale recommandée pour une ligne
-.Pq section Sx LA LONGUEUR DES LIGNES .
-.Pp
-Pour expliciter le contexte général d'un fichier, en terme d'utilisation
-ou d'architecture logicielle, insérer un commentaire en en-tête du
-fichier en laissant les caractères d'ouverture ou de fermeture de
-commentaires sur une ligne séparée :
-.Bd -literal -offset Ds
-/*
- * Interface de programmation des tableaux extensibles.
- * Cette structure de données peut être utilisée avec des
- * types de données qui ne nécessitent pas de processus
- * d'initialisation ou de libération et qui peuvent être
- * copiés bit à bit
- */
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES FICHIERS D'EN-TÊTE
-Inclure les fichiers d'en-tête dans l'ordre qui suit :
-.Bl -enum -compact
-.It
-les en-têtes locaux au programme ;
-.It
-les en-têtes des dépendances du programme ;
-.It
-les en-têtes systèmes et ceux de la bibliothèque C standard.
-.El
-.Pp
-Les fichiers d'en-tête sont ainsi inclus dans l'ordre décroissant de
-leur niveau d'abstraction.
-Cet ordre participe à garantir que chaque fichier d'en-tête inclus les
-en-têtes dont il a lui même besoin, indépendamment des directives
-d'inclusion qui précèdent sa propre inclusion.
-Si ce n'est pas le cas, la compilation pourra échouer, symptôme qu'un
-des fichiers d'en-tête n'est pas auto-consistant.
-.Pp
-Dans chaque groupe, trier les directives d'inclusion par ordre
-alphabétique des fichiers d'en-tête.
-Si besoin, ajouter un commentaire court, sur la même ligne que la
-directive d'inclusion, qui explicite la raison pour laquelle la fichier
-est inclus.
-.Bd -literal -offset Ds
-#include "bar.h"
-#include "foo.h"
-#include "qux.h"
-
-#include <baz.h>
-
-#include <float.h> /* FLT_MAX */
-#include <stdio.h>
-.Ed
-.Pp
-S'efforcer de n'inclure que les seuls fichiers d'en-tête
-réellement nécessaires au fichier ;
-par exemple par une déclaration anticipée des types structurés à
-la place d'inclure des en-têtes dans le seul but de déclarer lesdits
-types.
-Un enjeu a considérer avec d'autant plus d'attention que le fichier
-concerné par les inclusions est lui même un fichier d'en-tête, par
-conséquent amené à être lui même inclus.
-L'objet étant de limiter autant que possible le nombre de fichiers
-inclus par unité de compilation, pour limiter les accès disque et ainsi
-réduire les temps de compilation.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LA VISIBILITÉ DES SYMBOLES
-Par défaut, n'exposer aucun symbole
-.Po
-option
-.Fl fvisibility=hidden
-du compilateur
-.Xr gcc 1
-.Pc ,
-à l'exception de ceux de l'interface de programmation d'une
-bibliothèque.
-.\""""""""""""""""""""""""""""""""""
-.Ss Les symboles d'interface
-Privilégier l'écriture d'un seul fichier d'en-tête pour exposer
-l'interface de programmation d'une bibliothèque.
-Y définir une macro qui exporte les symboles qu'elle déclare dès lors
-que ce fichier d'en-tête est inclus par une unité de compilation de la
-bibliothèque.
-Et qui se contente d'importer ces mêmes symboles si ce même fichier est
-inclus par un programme tiers :
-.Bd -literal -offset Ds
-#include <rsys/rsys.h>
-
-#if defined(FOO_SHARED_BUILD)
- #define FOO_API extern EXPORT_SYM
-else
- #define FOO_API extern IMPORT_SYM
-#endif
-.Ed
-.Pp
-Avec :
-.Bl -dash -compact
-.It
-.Sy FOO_SHARED_BUILD
-une macro définie uniquement à la compilation de la bibliothèque
-.Po
-option
-.Fl DFOO_SHARED_BUILD
-du compilateur C
-.Pc Ns
- ;
-.It
-.Sy EXPORT_SYM
-et
-.Sy IMPORT_SYM
-des directives définies dans la bibliothèque
-.Ql RSys .
-Elles enrichissent le langage C d'une gestion explicite de la visibilité
-des symboles.
-.El
-.Pp
-Utiliser cette macro à la déclaration des variables et constantes
-d'interfaces :
-.Bd -literal -offset Ds
-/* Variables globales de l'interface de programmation */
-FOO_API const struct foo foo_plugh;
-FOO_API const struct foo foo_xyzzy;
-.Ed
-.Pp
-Déclarer le prototype des fonctions d'interface entre les directives
-.Sy BEGIN_DECLS
-et
-.Sy END_DECLS ,
-elles aussi définies dans la bibliothèque
-.Ql RSys
-.Pq en-tête In rsys/rsys.h .
-Ainsi, le fichier d'en-tête peut être inclus par un programe C++ :
-.Bd -literal -offset Ds
-BEGIN_DECLS
-
-FOO_API void
-foo_bar
- (int i,
- int* j);
-
-FOO_API int
-foo_qux
- (double d,
- int i);
-
-END_DECLS
-.Ed
-.\""""""""""""""""""""""""""""""""""
-.Ss Les symboles internes partagés
-Pour les fichiers d'en-tête internes au programme, utiliser la directive
-.Sy LOCAL_SYM ,
-définie dans le fichier
-.In rsys/rsys.h
-de la bibliothèque
-.Ql RSys ,
-pour déclarer les variables globales et prototypes de fonctions.
-Ainsi leur symbole n'est pas exposé à l'extérieur du programme.
-.Bd -literal -offset Ds
-#include <rsys/rsys.h>
-
-extern LOCAL_SYM char bar[128];
-
-extern LOCAL_SYM void
-quux
- (char* tab,
- size_t length);
-.Ed
-.Pp
-Cette directive est redondante si le compilateur est configuré pour
-masquer par défaut tous les symboles
-.Po
-option
-.Fl fvisibility=hidden
-de
-.Xr gcc 1
-.Pc .
-Utiliser
-.Sy LOCAL_SYM
-permet néanmoins de s'exonérer de cet a priori, tout en uniformisant
-les déclarations des fonctions et variables en explicitant pour chaque
-déclaration la visibilité du symbole associé.
-.\""""""""""""""""""""""""""""""""""
-.Ss Les symboles internes à une unité de compilation
-Utiliser le mot clé
-.Ql static
-pour déclarer des variables, constantes, et fonctions visibles
-uniquement au sein d'une unité de compilation.
-.Pp
-C'est notamment le cas des constantes symboliques structurées :
-.Bd -literal -offset Ds
-struct foo {
- int bar;
- int qux;
-};
-static const struct foo FOO_DEFAULT = {1, 0};
-.Ed
-.Pp
-Mais aussi des fonctions utilitaires, qu'elles soient
-propres à un fichier C, ou définies dans un fichier d'en-tête.
-.Bd -literal -offset Ds
-static void
-hello(void)
-{
- printf("Hello, world!\en");
-}
-.Ed
-.Pp
-Ces fonctions peuvent en plus être déclarées avec la directive
-.Sy INLINE ,
-définie dans l'en-tête
-.In rsys/rsys.h
-de la bibliothèque
-.Ql RSys ,
-pour suggérer au compilateur de substituer l'appel de la fonction par le
-corps de celle-ci, de sorte à éviter le surcoût de l'appel.
-Cette directive est équivalente au mot clé
-.Ql inline
-du C99, indisponible dans le dialecte C retenu
-.Pq section Sx LE LANGAGE C .
-.Bd -literal -offset Ds
-static INLINE void
-foo(void)
-{
- printf("bar\en");
-}
-.Ed
-.Pp
-Limiter la directive
-.Sy INLINE
-aux fonctions élémentaires, destinées à être appelées fréquemment et
-dont le coût de l'appel pourrait alors s'avérer significatif.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES BLOCS
-Ouvrir chaque bloc sur la même ligne que la directive qui en est à
-l'origine
-.Po
-.Ql do ,
-.Ql enum
-.Ql for ,
-.Ql if ,
-.Ql struct ,
-.Ql switch ,
-.Ql union ,
-.Ql while
-.Pc ,
-en séparant par un espace la fin de la directive et le caractère
-.Ql {
-qui marque l'ouverture du bloc :
-.Bd -literal -offset Ds
-if (foo) {
- bar();
- qux();
-}
-.Ed
-.Pp
-Exception faite des fonctions, ou le bloc associé est ouvert sur la
-ligne qui suit :
-.Bd -literal -offset Ds
-static void
-foo(void)
-{
- printf("bar\en");
-}
-.Ed
-.Pp
-Fermer un bloc sur une ligne à part sauf s'il est suivi d'une nouvelle
-structure de contrôle associée à la précédente
-.Po
-.Ql if else ,
-.Ql do while
-.Pc .
-Dans ce cas, ajouter la nouvelle instruction sur la même ligne que celle
-utilisée pour fermer le bloc, en la séparant du caractère
-.Ql }
-par un espace.
-.Pp
-Aligner la fermeture du bloc à l'indentation de sa directive, ou, dans
-le cas de directives qui se suivent, à l'indentation de la première
-directive à l'origine des blocs successifs :
-.Bd -literal -offset Ds
-if (foo) {
- bar();
-} else {
- qux();
-}
-.Ed
-.Pp
-Écrire sur une seule ligne une directive et les opérations qu'elle
-contrôle que si la clarté du code n'en est pas impactée.
-Dans ce cas, l'ouverture et la fermeture du bloc associé se fait sur une
-seule et même ligne :
-.Bd -literal -offset Ds
-if (foo) { bar(); return 0; }
-.Ed
-.Pp
-Ne pas utiliser d'accolades si la structure de contrôle n'est suivie
-d'aucune ou d'une seule directive écrite sur la même ligne :
-.Bd -literal -offset Ds
-while (foo());
-
-if (bar) return 0;
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES MOTS CLÉS
-Ajouter un espace après chaque structure de contrôle
-.Ql if ,
-.Ql switch ,
-.Ql for
-et
-.Ql while
-pour les différencier des appels de fonctions.
-Ne pas ajouter d'espace après l'ouverture et avant la fermeture des
-parenthèses qui détourent leur(s) expression(s) :
-.Bd -literal -offset Ds
-if (i < 10) {
- foo(i);
-}
-.Ed
-.Pp
-Ajouter un espace après chaque point virgule qui sépare les expressions
-d'une boucle
-.Ql for
-sauf si l'expression qui suit est vide :
-.Bd -literal -offset Ds
-for (i=0; i<10; foo(i++));
-
-for (;;) { /* Boucle infinie */
- poll();
- if(bar) break;
-}
-.Ed
-.Pp
-Assimiler l'instruction
-.Ql sizeof
-à une fonction ; ne pas insérer d'espace entre le mot clé et son
-expression entourée de parenthèses :
-.Bd -literal -offset Ds
-sz = sizeof(int);
-.Ed
-.\""""""""""""""""""""""""""""""""""
-.Ss L'instruction Ql switch
-Limiter à quelques lignes le contenu de chaque
-.Ql case
-d'une instruction
-.Ql switch ,
-celle-ci devant donner à lire la seule répartition des traitements,
-fonction de la valeur que peut prendre l'expression du
-.Ql switch .
-Et non les traitements eux même, sauf s'ils sont triviaux.
-Un
-.Ql case
-au contenu trop fourni est alors le signe d'un manque de structure dans
-l'écriture du programme.
-.Pp
-Toujours ajouter une instruction
-.Ql default
-même si l'ensemble des valeurs que pourraient prendre l'expression du
-.Ql switch
-est censé être couvert par les différents
-.Ql case .
-C'est notamment le cas quand l'expression est une variable
-d'énumération.
-Utiliser alors la directive
-.Sy FATAL ,
-définie par la bibliothèque
-.Ql RSys
-.Pq en-tête In rsys/rsys.h ,
-pour signifier un comportement inattendu.
-Et ainsi pouvoir diagnostiquer une erreur dans la valeur de l'expression
-du
-.Ql switch ,
-ou un
-.Ql case
-manquant :
-.Bd -literal -offset Ds
-switch (i) {
- case FOO: foo(); break;
- case BAR: bar(); break;
- case QUX: qux = 1; break;
- default: FATAL("Unreachable code\en"); break;
-}
-.Ed
-.Pp
-Ajouter la directive
-.Sy FALLTHROUGH ,
-définie dans le fichier d'en-tête
-.In rsys/rsys.h
-de la bibliothèque
-.Ql RSys ,
-en fin des instructions
-.Ql case
-qui s'enchaînent.
-L'ajout de cette directive permet d'expliciter que c'est bien le
-comportement attendu et non l'oublie d'une instruction
-.Ql break ,
-en plus d'éviter un possible message d'avertissement à la compilation
-.Pq option Fl Wimplicit-fallthrough No de Xr gcc 1 Ns
- :
-.Bd -literal -offset Ds
-switch (c) {
- case 'a':
- foo = 1;
- FALLTHROUGH;
- case 'b':
- bar = 1;
- break;
- default:
- usage();
- break;
-}
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LE NOMMAGE
-.\""""""""""""""""""""""""""""""""""
-.Ss Les variables
-Nommer les variables en minuscules.
-Utiliser le tiret bas
-.Ql _
-au titre de séparateur entre les termes utilisés dans le nom des
-variables :
-.Bd -literal -offset Ds
-foo_bar
-.Ed
-.Pp
-Expliciter l'objet d'une variable dans son nom avec d'autant plus de
-précision que sa portée est grande.
-Une variable locale à un bloc de quelques lignes pourra se contenter
-d'un nom abrégé tel que
-.Va tmp
-pour un résultat temporaire, voire n'être qu'un seul caractère
-pour un indice
-.Va i
-ou un nombre d'éléments
-.Va n Ns
- ; leur contexte d'utilisation venant préciser ce que leur nom résume.
-Ce nom abrégé vient non seulement alléger l'écriture mais aussi en
-renforcer l'expressivité.
-Par exemple
-.Va tableau Ns Bq Va i
-reste plus clair que
-.Va tableau Ns Bq Va indice .
-.Pp
-Les variables globales sont au contraire à nommer de sorte à décrire ce
-qu'elles représentent, indépendamment de tout contexte d'utilisation,
-par construction distant de leur déclaration.
-Un compteur d'allocations global à un programme aura donc pour nom
-.Va compteur_allocations
-plutôt que
-.Va cpt_allocs .
-.Pp
-Pour une variable globale déclarée au niveau de l'interface d'une
-bibliothèque, préfixer ladite variable avec l'acronyme de la
-bibliothèque.
-Un compteur d'allocation global à la bibliothèque
-.Ql Foo ,
-et déclaré en tant que variable globale de son interface, sera alors
-nommé
-.Va foo_compteur_allocations .
-.\""""""""""""""""""""""""""""""""""
-.Ss Les fonctions
-Nommer les fonctions avec des caractères alphanumérique en minuscules,
-et séparer les termes qui composent leur nom par un tiret bas
-.Pq caractère Ql _ .
-.Pp
-Donner à une fonction un nom d'autant plus explicite que sa portée est
-importante.
-Une fonction utilitaire pourra se contenter d'un nom abrégé, tel que
-.Fn cmp
-pour une fonction de comparaison utilisée comme argument d'un appel à
-.Xr qsort 3
-au sein d'un fichier C.
-Là où une fonction partagée entre plusieurs unités de compilation aura
-un nom plus expressif, tel que
-.Fn compare_bar ,
-pour notamment expliciter le type
-.Vt struct bar
-des variables comparées.
-Jusqu'à préfixer le nom de la fonction par l'acronyme de la bibliothèque
-quand elle est une fonction d'interface de ladite bibliothèque.
-Pour la bibliothèque
-.Ql Foo ,
-une fonction d'interface sera alors nommée
-.Fn foo_compare_bar .
-.\""""""""""""""""""""""""""""""""""
-.Ss Les déclarations de types
-Utiliser des caractères alphanumériques en minuscules pour nommer les
-structures, unions et énumérations.
-Utiliser le tiret bas
-.Ql _
-pour séparer les différents termes qui composent leur nom.
-.Bd -literal -offset Ds
-struct foo {
- int bar;
- int baz
-};
-
-union foo_bar {
- double qux;
- int xyzzy;
-};
-.Ed
-.Pp
-Utiliser la même convention pour nommer les déclarations typedef.
-À l'exception du suffixe
-.Ql _T
-ajouté au nom de l'identificateur du type, en écho au suffixe
-.Ql _t
-souvent utilisé pour ce type de déclaration, mais réservé par le
-standard POSIX.
-.Bd -literal -offset Ds
-typedef int foo_T;
-typedef char foo_bar_T[256];
-.Ed
-.Pp
-Ne pas utiliser de déclaration typedef sur les structures, unions et
-énumérations de sorte à permettre leur déclaration anticipée.
-.Pp
-Préfixer le nom d'un type par l'acronyme de la bibliothèque dès lors
-qu'il est un type déclaré en tant que type de son interface.
-Par exemple, un type structuré de l'interface de la bibliothèque
-.Ql Foo
-sera nommé
-.Vt struct foo_mon_type .
-.\""""""""""""""""""""""""""""""""""
-.Ss Constantes et macros
-Utiliser des majuscules pour nommer les constantes symboliques, qu'elles
-soient des macros, des constantes énumérées, ou des variables déclarées
-comme constantes.
-Séparer par un tiret bas
-.Ql _
-les termes qui composent leur nom :
-.Bd -literal -offset Ds
-#define FOO_BAR 42
-
-enum foo {
- BAR_BAZ,
- QUX
-};
-
-static const enum foo FOO_XYZZY = BAR_BAZ;
-.Ed
-.Pp
-Nommer une constante ou une macro de manière d'autant plus explicite
-que sa portée est importante.
-Une constante définie localement à une fonction pourra se contenter
-d'un nom abrégé, jusqu'à n'être qu'un seul caractère, par exemple pour
-un nombre d'éléments constant
-.Sy N .
-Là où le nom d'une macro ou d'une constante définie dans un fichier
-d'en-tête se devra d'être plus explicite, tel que
-.Sy NOMBRE_ELEMENTS_MAX .
-Et être préfixée par l'acronyme de la bibliothèque si elle est déclarée
-comme macro ou constante de son interface.
-Par exemple, pour la bibliothèque
-.Ql Foo ,
-.Sy FOO_NOMBRE_ELEMENTS_MAX .
-.Pp
-Utiliser la convention typographique dite
-.Dq camel case
-pour nommer les arguments des macros ;
-les termes qui composent leur nom sont séparés par une variation de la
-casse typographique.
-Un terme débute par une majuscule, suivi de caractères
-alphanumériques en minuscules.
-.Bd -literal -offset Ds
-#define FOO_BAR(FooBar, Qux) ((FooBar) + (Qux))
-.Ed
-.Pp
-Ainsi, les arguments de macros sont différenciés des constantes
-symboliques et des variables.
-.Pp
-À noter que la macro elle même est nommée selon la même convention que
-celle utilisée pour les constante symboliques
-.Pq en majuscule et un tiret bas pour séparer ses différents termes .
-La parenthèse ouvrante, collée au nom de la macro, permettant de
-différencier les 2 cas.
-.\""""""""""""""""""""""""""""""""""
-.Ss Les variables et macros internes
-Suffixer par deux tirets bas
-.Ql __
-les variables membres d'une structure définie publiquement, qui n'ont
-cependant une signification qu'en interne des fonctions d'interface de
-la structure.
-L'enjeu étant de souligner que ces variables ne sont accessibles que par
-effet de bord, et ne s'addressent
-.Em pas
-aux utilisatrices et utilisateurs, qui ne devraient donc pas y accéder
-directement :
-.Bd -literal -offset Ds
-struct foo {
- double bar;
- int baz;
- int* qux__; /* Variable interne */
-};
-.Ed
-.Pp
-Utiliser le même suffixe en double tirets bas
-.Ql __
-pour nommer les variables internes à une macro, afin d'éviter de masquer
-les variables définies dans le contexte où la macro est développée :
-.Bd -literal -offset Ds
-#define FOO(Bar, N) { \e
- int i__; \e
- for (i__ = 0; i__ < N; Bar(i__), ++i__); \e
-} (void)0
-.Ed
-.Pp
-Suffixer les macros d'un fichier d'en-tête par deux tirets bas
-.Ql __
-dès lors qu'elles sont propres au fichier d'en-tête, et donc
-vraisemblablement inacessibles au delà :
-.Bd -literal -offset Ds
-#define FOO__(Type, Dim) \e
- struct Type { \e
- int i[Dim]; \e
- float f[Dim]; \e
- }
-FOO__(bar, 2);
-FOO__(baz, 3);
-FOO__(qux, 4);
-#undef FOO__
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES FONCTIONS
-S'attacher à ce que chaque fonction reste simple et concise, en ne
-s'appliquant à ne lui faire faire qu'une seule chose.
-Ce faisant, le corps d'une fonction devrait être lisible sur un ou deux
-écran, avec comme référence la taille des terminaux telle que
-démocratisée à la fin des années 1970, à savoir 24 lignes.
-.Pp
-Un indice quant à la taille qu'une fonction devrait s'efforcer à avoir
-est donné par ses niveaux d'indentation.
-Plus elle compte de niveaux et plus elle devrait être ramassée.
-De même, un nombre de variables locales supérieur à dix peut être le
-signe d'une fonction trop dense.
-.Pp
-Écrire les directives qui contrôlent la portée d'une fonction et son
-type de retour sur une ligne séparée de son nom.
-L'expression régulière
-.Ql ^nom_de_fonction
-peut ainsi être utilisée pour la recherche d'une fonction dans les
-différents fichiers sources.
-.Pp
-Pour une déclaration, revenir à la ligne avant d'ouvrir la parenthèse de
-la fonction, précédée d'une indentation par rapport au nom de la
-fonction sur la ligne qui précède.
-Puis, lister les arguments de la fonction, en revenant à la ligne après
-chacun d'eux et en les alignant les uns par rapport aux autres.
-Ajouter la parenthèse fermante
-.Ql \&)
-et le point virgule
-.Ql \&;
-sur la ligne du dernier argument, sans espace supplémentaire :
-.Bd -literal -offset Ds
-extern LOCAL_SYM void
-foo_bar
- (struct foo* foo,
- const int qux,
- const float xyzzy);
-.Ed
-.Pp
-Les différentes parties qui composent le profil de la fonction sont
-ainsi identifiables par la seule mise en page de sa déclaration.
-.Pp
-Lors de sa définition, lister les arguments de la fonction sur la même
-ligne que le nom de la fonction, sans ajouter d'espace entre le nom de
-la fonction et sa parenthèse ouvrante :
-.Bd -literal -offset Ds
-void
-foo_bar(struct foo* foo, const int qux, const float xyzzy)
-{
- ...
-}
-.Ed
-.Pp
-Si la liste des arguments dépasse la longueur maximale d'une ligne
-.Pq section Sx LA LONGUEUR DES LIGNES
-les lister comme pour une déclaration.
-.Pp
-Ordonner les arguments d'une fonction comme suit :
-.Bl -enum -compact
-.It
-pour une fonction d'interface, la variable sur laquelle la fonction
-opère ;
-.It
-les données d'entrées ;
-.It
-les données en sortie.
-.El
-.Pp
-Ajouter l'instruction
-.Ql const
-aux variables qui n'ont pas vocation à être modifiées par la fonction.
-Et ce quand bien même leur modification n'aurait aucune conséquence,
-comme pour les variables de données simples, copiées à l'appel de la
-fonction.
-L'objet étant de souligner qu'elles sont des variables en entrée :
-.Bd -literal -offset Ds
-static void
-foo
- (struct foo* foo,
- constr struct bar* bar,
- const int longueur,
- const int* liste,
- int* resultat);
-
-static INLINE double
-madd(const double a, const double b, const double c)
-{
- return a*b + c;
-}
-.Ed
-.Pp
-Ne passer en copie que les seuls paramètres en entrée de la fonction de
-type primitif
-.Pq Vt char , int , double , No énumération, ... .
-Utiliser un pointeur constant dès lors que le paramètre d'entrée est
-de type structuré, afin d'éviter le surcoût de sa copie à chaque appel de
-fonction ; son occupation mémoire étant a priori plus important
-qu'une donnée simple.
-.Pp
-Les paramètres d'une fonction peuvent ne pas être utilisés à l'intérieur
-de celle-ci.
-C'est notamment le cas si les paramètres ne sont utiles que pour
-répondre à un profil de fonction spécifique ou dans un contexte de
-compilation particulier, par exemple pour le débogage.
-Lister ces paramètres en en-tête de la fonction, après
-la définition des variables locales, en les préfixant d'une conversion
-explicite vers un type vide :
-.Bd -literal -offset Ds
-static void
-foo(int x, int y, int z)
-{
- int i = 0;
- (void)y, (void)z; /* Paramètres inutilisés */
-
- i = bar(x);
- if (i < 42) {
- printf("Foobar\en");
- }
-}
-.Ed
-.Pp
-Cette conversion explicite quels paramètres sont ignorés, en plus de
-désactiver les avertissements de compilation quant à la définition de
-paramètres non utilisés
-.Pq option Fl Wunused-parameter No de Xr gcc 1 .
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES VARIABLES
-Limiter le nombre de variables par bloc entre 5 et 10.
-Un nombre de variables trop important peut être le signe d'un manque de
-structure auquel un découpage en sous-fonction(s) pourrait remédier
-.Pq section Sx LES FONCTIONS .
-.Pp
-Initialiser les variables dès leur définition avec sinon une valeur
-valide, au moins une valeur par défaut.
-L'objet étant d'éviter l'utilisation de variables non initialisées.
-D'apparence peu critique pour les variables de type primitif, cette
-initialisation l'est bien plus pour les variables structurées, dont la
-liste des membres peut changer.
-Si elle existe, utiliser la constante proposée avec la définition du
-type structuré pour initialiser ses membres
-.Pq voir section Sx LES STRUCTURES .
-En son absence, n'initialiser que le premier membre de la variable ; le
-language C assure alors que les autres membres seront initialisés à
-zéro.
-De même pour un tableau alloué sur la pile, initialiser son premier
-élément suffit à garantir que le reste du tableau sera initialisé à
-zero :
-.Bd -literal -offset Ds
-struct foo foo = FOO_DEFAULT;
-struct bar bar = {0};
-int qux[10] = {0};
-int i = 0;
-.Ed
-.Pp
-Au sein d'une même fonction, définir les variables au plus proche de
-leur utilisation de sorte à ce que le contexte dans lequel elles sont
-utilisées participe à les caractériser.
-Par exemple, une variable
-.Va i
-utilisée dans un bloc comme variable temporaire, et comme indice de
-boucle dans un autre, gagnera en expressivité et en robustesse à être
-définie localement à chaque bloc ;
-les deux variables étant alors, par construction, non seulement séparées
-mais aussi sans effet de bord de l'une sur l'autre :
-.Bd -literal -offset Ds
-if(foo) {
- const int i = bar();
- if (i > max_i) max_val = i;
- if (i < min_i) min_val = i;
-} else {
- int i = 0;
- for(i = 0; i < N; ++i) qux(i);
-}
-.Ed
-.Pp
-Regrouper les définitions des variables dès lors qu'elles sont liées
-sémantiquements.
-Les trier ensuite par taille mémoire décroissante, et enfin par ordre
-alphabétique :
-.Bd -literal -offset Ds
-/* Bibliothèque Foo */
-struct foo_args foo_args = FOO_ARGS_DEFAULT;
-struct foo* foo = NULL;
-
-/* Tableau à traiter */
-double* liste = NULL;
-int capacite = 0;
-int longueur = 0;
-.Ed
-.Pp
-Trier la définition des variables par taille mémoire tend à limiter le
-nombre d'octets de remplissage que le compilateur C ajoute pour garantir
-l'alignement mémoire de chaque variable eu égard à leur type.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES CONSTANTES
-Utiliser une énumération si les constantes à définir sont liées
-sémantiquement, et une macro sinon :
-.Bd -literal -offset Ds
-#define ID_INVALIDE ((unsigned)-1)
-
-enum { X, Y, Z };
-
-enum attribut {
- POSITION,
- NORMALE,
- TEXCOORD
-};
-.Ed
-.Pp
-Pour une énumération qui utilise des valeurs par défaut,
-ajouter si besoin une dernière constante qui définit le nombre de
-constantes valides ;
-sa valeur sera ainsi automatiquement mise à jour à chaque changement de
-l'énumération.
-Une telle constante peut alors servir à définir la cardinalité d'un
-tableau, comme valeur du dernier indice marquant la fin d'une itération,
-ou encore comme valeur vis à vis de laquelle la validité d'une variable
-du type énuméré peut être vérifiée :
-.Bd -literal -offset Ds
-enum molecule {
- CH4,
- CO,
- CO2,
- H2O,
- N2O,
- O3,
-
- NOMBRE_DE_MOLECULES
-};
-
-/* Vérifier qu'une constante définie une molecule valide */
-#define MOLECULE_EST_VALIDE(Mol) \e
- ((unsigned)(Mol) < NOMBRE_DE_MOLECULES)
-
-static const char* NOM_DES_MOLECULES[NOMBRE_DE_MOLECULES] = {
- "CH4", "CO", "CO2", "H2O", "N2O", "O3"
-};
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES STRUCTURES
-Définir les structures en en-tête de fichier
-.Pq section Sx LA STRUCTURE D'UN FICHIER SOURCE ,
-à l'exeption des structures locales à une fonction.
-.Pp
-Lister les variables membres d'une structure suivant la même convention
-que pour la définition des variables d'un bloc
-.Pq section Sx LES VARIABLES Ns
- :
-les regrouper d'abord par sémantique, puis les trier par occupation
-mémoire décroissante, et enfin par ordre alphabétique.
-.Pp
-Ne définir qu'une variable membre par ligne.
-.Pp
-Pour une structure dont aucune fonction ne permet d'en initialiser les
-membres, définir une constante qui fixe leur valeur par défaut.
-Suffixer cette constante par
-.Ql DEFAULT
-ou
-.Ql NULL
-fonction de si une variable structurée ainsi initialisée est une donnée
-valide ou non.
-Déclarer cette constante en tant que variable statique et l'initialiser par
-une macro de même nom, différenciée de la variable constante par un
-double tiret bas final
-.Ql __ Ns
- :
-.Bd -literal -offset Ds
-struct arg {
- char* fichier; /* NULL <=> entrée standard */
- int verbosite;
-};
-#define ARG_DEFAULT__ {NULL, 0}
-static const struct arg ARG_DEFAULT = ARG_DEFAULT__;
-
-struct chaine {
- char* mem;
- int longueur;
- int capacite;
-};
-#define CHAINE_NULL__ {NULL,0,0}
-static const struct chaine CHAINE_NULL = CHAINE_NULL__;
-.Ed
-.Pp
-N'utiliser la macro que lorsqu'il est impossible d'utiliser la variable
-constante, en l'occurence pour initialiser, dès sa définition, les
-membres d'une autre variable structurée :
-.Bd -literal -offset Ds
-struct qux {
- struct chaine foo;
- int bar;
-};
-#define QUX_DEFAULT__ {CHAINE_NULL__, 0}
-static const struct qux QUX_DEFAULT = QUX_DEFAULT__;
-.Ed
-.Pp
-Éviter d'utiliser une déclaration typedef des structures afin
-d'autoriser leur déclaration anticipée.
-Et l'utilisation de pointeur vers une donnée structurée sans avoir sa
-définition.
-Si un déclaration typedef est néanmoins souhaitée, nommer le type
-structuré en suivant la convention de nommage des déclarations typedef
-.Pq section Sx Les déclarations de types .
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES MACROS
-Pour définir une séquence d'instructions,
-préférer l'utilisation de fonctions aux macros.
-Déclarer la fonction avec la directive
-.Sy INLINE
-si son coût d'appel est un enjeu
-.Pq section Sx Les symboles internes à une unité de compilation .
-.Pp
-Regrouper la séquence d'instructions d'une macro dans un bloc terminé
-par l'instruction
-.Ql (void)0 .
-Elle peut ainsi être utilisée comme unique expression d'une structure de
-contrôle, et force l'ajout d'un point virgule
-.Ql \&;
-.Pq ou d'une virgule Ql \&,
-après son utilisation, telle n'importe quelle autre instruction C.
-.Pp
-En C, il est plus courant d'encapsuler les instructions d'une macro
-dans une structure de contrôle
-.Ql do { ... } while (0)
-plutôt que dans un bloc terminé par la converstion de l'entier zéro vers
-un type vide
-.Ql (void)0 .
-Si les deux écritures répondent aux mêmes objectifs, cette dernière
-convention évite les avertissements émis par certains compilateurs quant
-à l'utilisation d'une expression conditionnelle constante dans
-.Ql while (0) .
-.Pp
-Ouvrir le bloc sur la même ligne que le nom de la macro, en ajoutant un
-espace avant l'acolade
-.Ql { .
-Indenter le contenu du bloc par rapport à la directive de définition de
-la macro.
-Justifer à droite les caractères anti-slash
-.Ql \e
-en fin de chaque ligne de sorte à faciliter la lecture de la séquence
-d'instructions développée par la macro :
-.Bd -literal -offset Ds
-#define FOO(X, Y) { \e
- if ((X) == (Y)) printf("Bar \en"); \e
- (Y) += 2; \e
-} (void)0
-.Ed
-.Pp
-À noter que dans l'exemple qui précède, les caractères anti-slash
-.Ql \e
-sont alignés en suivant des contraintes d'édition propres à ce manuel.
-Dans un fichier source, positioner l'anti-slash en tant que dernier
-caractère de lignes qui occupent la longueur maximale autorisée
-.Pq section Sx LA LONGUEUR DES LIGNES .
-.Pp
-Pour une macro dont la portée est l'unité de compilation, ne pas changer
-le déroulé des instructions de son contexte d'appel, par exemple en
-intégrant une directive
-.Ql return .
-Son utilisation contredirait l'exécution séquentielle du code et ce
-faisant nuirait à sa lisibilité.
-Il n'est donc
-.Em pas
-recommandé de définir une macro comme suit :
-.Bd -literal -offset Ds
-#define FOO(X) {
- if (bar(X))
- return -1;
-} (void)0
-.Ed
-.Pp
-Ne pas présupposer l'existance de variables externes à la macro,
-exeption faite des variables globales.
-L'objet étant de ne pas lier son bon fonctionnement au contexte local
-dans lequel elle est développée.
-L'écriture qui suit est donc
-.Em découragée Ns
- :
-.Bd -literal -offset Ds
-#define BAR(X,Y) {
- z = (X) + (Y);
- if (xyzzy(z))
- z += 1;
-}
-.Ed
-.Pp
-Contrairement aux macros définies à l'échelle d'une unité de
-compilation, une macro locale peut non seulement changer le fil
-d'exécution du contexte d'appel, mais aussi utiliser des variables
-externes.
-Et ce précisément en raison de son caractère local, qui lie étroitement
-la macro à son seul contexte d'utilisation.
-.Bd -literal -offset Ds
-static int
-foo(const int x)
-{
- char s[10] = {0};
- int line = 0;
- int err = 0;
-
- #define CALL(Func) { \e
- if((err=(Func)) != 0) { \e
- line = __LINE__; \e
- goto error; \e
- } \e
- } (void)0
-
- CALL(bar(x, s));
- CALL(quux(s));
-
- #undef CALL
-
-exit:
- return err;
-error:
- fprinf(stderr, "erreur %d ligne %d\en", err, line);
- goto exit;
-}
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES ALLOCATIONS DYNAMIQUES
-Préférer l'interface d'allocation proposée par la
-bibliothèque
-.Ql RSys
-via son fichier d'en-tête
-.In rsys/mem_allocator.h .
-Elle enrichit la gestion de la mémoire dynamique proposée par la
-bibliothèque C standard, notamment en enregistrant la quantité de
-mémoire allouée.
-.Pp
-Utiliser dès lors les fonctions
-.Fn mem_alloc ,
-.Fn mem_calloc
-et
-.Fn mem_realloc
-pour allouer dynamiquement de la mémoire.
-Leur profil est celui des fonctions équivalentes proposées par la
-bibliothèque C, à savoir ces mêmes fonctions mais sans le prefixe
-.Ql mem_
-.Po
-voir
-.Xr alloc 3 ,
-.Xr calloc 3 ,
-et
-.Xr realloc 3
-.Pc .
-.Pp
-Privilégier la fonction
-.Fn mem_calloc
-à
-.Fn mem_alloc
-de sorte à initialiser la mémoire allouée à zéro, et d'éviter ainsi
-d'utiliser des données non initialisées.
-.Pp
-Ne pas convertir le pointeur retourné par les fonctions d'allocation.
-La conversion d'un pointeur vide vers n'importe quel autre type de
-pointeur est déjà assuré par le langage C.
-.Pp
-Définir la taille du bloc mémoire à allouer via le type pointé par la
-variable destination :
-.Bd -literal -offset Ds
-p = mem_calloc(42, sizeof(*p));
-.Ed
-.Pp
-L'alternative qui consiste à épeller le type pointé en argument de
-.Ql sizeof
-non seulement nuit à la lisibilité des sources, mais laisse en plus
-l'opportunité d'introduire un bogue dès lors que le type de pointeur
-est mis à jour mais pas le nom du type renseigné à
-.Ql sizeof .
-.Pp
-Utiliser la fonction
-.Fn mem_alloc_aligned
-pour allouer un bloc mémoire dont l'adresse doit être alignée sur un
-nombre d'octets spécifique.
-Utiliser la fonction
-.Xr memset 3 ,
-de la bibliothèque C standard, pour forcer la mise à zéro du bloc ainsi
-alloué sinon rempli d'octets
-aléatoires :
-.Bd -literal -offset Ds
-foo = mem_alloc_aligned(sizeof(*foo), 128/* Alignement */);
-memset(foo, 0, sizeof(*foo));
-.Ed
-.Pp
-Vérifier chaque allocation en testant que l'adresse retournée n'est pas
-.Ql NULL .
-Traiter ce cas comme une erreur et non un bogue
-.Pq section Sx CENTRALISER LA SORTIE D'UNE FONCTION Ns
- :
-.Bd -literal -offset Ds
- foo = mem_calloc(1, sizeof(*foo);
- if (!foo) {
- res = RES_MEM_ERR;
- goto error;
- }
-.Ed
-.Pp
-Libérer la mémoire allouée via
-.Ql RSys
-avec la fonction
-.Fn mem_rm
-dont le profil est le même que celui de la fonction
-.Xr free 3 Ns
- :
-.Bd -literal -offset Ds
-mem_rm(foo);
-.Ed
-.Pp
-Détecter la présence de fuites mémoires via la fonction
-.Fn mem_allocated_size
-qui retourne la quantité de mémoire qui reste allouée par la
-bibliothèque :
-.Bd -literal -offset Ds
-int
-main(void)
-{
- size_t sz = 0;
- int err = 0;
-
- ...
-
- if ((sz = mem_alloc_aligned()) != 0) {
- fprintf(stderr, "Fuites mémoires : %lu octets\en", sz);
- if (err == 0) err = 1;
- }
- return err;
-}
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Ss Les allocateurs mémoire
-Dans son fichier d'en-tête
-.In rsys/mem_allocator.h ,
-la bibliothèque
-.Ql RSys
-définit en plus une interface d'allocateur mémoire.
-Au contraire de son interface d'allocation qui enregistre la mémoire
-alloué globalement par la bibliothèque,
-chaque allocateur enregistre ses seules allocations.
-.Pp
-Plusieurs types d'allocateurs sont proposés par la bibliothèque
-.Ql RSys ,
-chacun mettant en oeuvre une politique d'allocation qui lui est propre.
-Si bien qu'en fonction du contexte, un type d'allocateur particulier
-peut s'avérer plus approprié, par exemple pour réduire les coûts
-d'allocations/désallocations.
-Décrire les différents types d'allocateurs définis dans la bibliothèque
-.Ql RSys
-sort du cadre de cette documentation.
-Le lecteur est invité à se référer à son fichier d'en-tête
-.In rsys/mem_allocator.h
-pour plus d'informations.
-.Pp
-Les convention listées précédemment quant aux allocation dynamiques
-s'appliquent à l'identique à l'utilisation des allocateurs.
-.Pp
-Utiliser un allocateur consiste à appeler des macros, dont le nom est
-une version en majuscule des fonctions de l'interface d'allocation.
-Avec en plus en premier argument l'addresse de l'allocateur concerné :
-.Bd -literal -offset Ds
-foo = MEM_CALLOC(&mem_default_allocator, 1, sizeof(*foo));
-
-\&...
-
-MEM_RM(&mem_default_allocator, foo);
-
-if (MEM_ALLOCATED_SIZE(&mem_default_allocator)) {
- fprintf(stderr, "Fuites mémoires\en");
-}
-.Ed
-.Pp
-avec
-.Va mem_default_allocator
-l'allocateur par défaut définit par la bibliothèque
-.Ql RSys .
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh CENTRALISER LA SORTIE D'UNE FONCTION
-Utiliser la directive
-.Ql goto
-pour centraliser les traitements à effectuer en sortie de fonction, tels
-les affectations de variables de sorties, les libérations de variables
-locales temporaires, ou le renvoie d'une valeur en retour de la fonction.
-Regrouper ces traitements en fin de fonction sous le label
-.Ql exit
-dont la dernière instruction est la valeur retournée par la fonction.
-.Pp
-De même, centraliser la gestion des erreurs détectées pendant
-l'exécutation de la fonction sous un label
-.Ql error ,
-qui vise à revenir à l'état du programme avant l'appel de la fonction,
-et à préparer son retour compte tenu de l'erreur.
-Ses traitements recouvrent notamment la libération de
-l'espace mémorie alloué à destination de l'appelant, la restauration des
-données en mise à jour modifiées par la fonction avant la détection de
-l'erreur, ou la définition de valeurs à destination des variables en
-sortie en conséquence de l'erreur détectée.
-.Pp
-Placer le label
-.Ql error
-après le label
-.Ql exit .
-Terminer la gestion des erreurs par la directive
-.Ql goto exit ,
-de sorte à effectuer les traitements en sortie,
-.Em indépendants
-de la présence ou non d'une erreur d'exécution, et donc à appliquer en
-toute circonstance.
-En structurant les labels de la sorte, les traitements en sortie
-.Pq label Ql exit
-sont ainsi exécutés soit automatiquement au fil du bon déroulé de la
-fonction, sans que l'auteur(e) n'est nécessairement à le préciser.
-Soit après la détection d'une erreur dont la gestion explicite via la
-directive
-.Ql goto error
-précède la sortie de la fonction et ses traitements associés ; auxquels
-renvoit finalement la gestion des erreurs centralisée sous le label
-.Ql error .
-.Bd -literal -offset Ds
-static res_T
-foo(const int bar, int** out_list)
-{
- int* list = NULL;
- res_T res = RES_OK;
-
- if (out == NULL) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- if ((list = mem_calloc(42, sizeof(*list)) == NULL) {
- res = RES_MEM_ERR;
- goto error;
- }
-
- if ((res = quux(bar, list)) != RES_OK) goto error;
-
-exit:
- if (out_list != NULL) *out_list = list;
- return res;
-error:
- if (list) { mem_rm(list); list = NULL; }
- goto exit;
-}
-.Ed
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh LES PROGRAMMES EN LIGNE DE COMMANDE
-Privilégier une interface en ligne de commande pour les programmes
-directement exécutables par l'utilisateur.
-À la fois simple et légère, elle s'intègre parfaitement aux shells, que
-ce soit en session interactive ou via des scripts.
-Avant d'être une interface utilisateur, elle est l'interface avec le
-système UNIX avec lequel le programme peut alors dialoguer, par exemple
-en terme de gestion des entrées/sorties ou de communication
-inter-processus.
-.Pp
-Analyser les arguments du programme en utilisant la fonction
-.Xr getopt 3
-définie par le standard POSIX.1-2001 dans l'en-tête
-.In unistd.h
-de la bibliohtèque C.
-Cette fonction assure la consistante de l'analyse des arguments et
-participe au respect des conventions énoncées par le standard POSIX pour
-les utilitaires en ligne de commandes.
-.Pp
-Proposer l'option
-.Fl h
-qui affiche le seul synopsis de la commande en guise de résumé de ses
-attendus et options.
-Réserver la description du programme et de ses options à sa page de
-manuel.
-Afficher ce même synopsis en cas d'erreur lors de l'analyse des
-arguments de sorte à renvoyer l'utilisateur vers la syntaxe de la
-commande.
-.Bd -literal -offset Ds
-static void
-usage(FILE* stream)
-{
- fprintf(stream, "usage: foo [-hv] [-b bar]\en");
-}
-
-int
-main(int argc, char** argv)
-{
- FILE* bar = NULL;
- int err = 0;
- int opt = 0;
- int verbosity = 0;
-
- while ((opt = getopt(argc, argv, "b:hv")) != -1) {
- switch (opt) {
- case 'a':
- if((bar = fopen(optarg, "r")) == NULL) err = 1;
- break;
- case 'h': usage(stdout); goto exit;
- case 'v': verbosity += (verbosity < 3); break;
- default: err = 1; break;
- }
- if (err) { usage(stderr); goto error; }
- }
- if (bar == NULL) bar = stdin;
-
- if ((err = foo(bar, verbosity)) != 0) goto error;
-
-exit:
- if(bar && bar != stdin) fclose(bar);
- return err;
-error:
- goto exit;
-}
-.Ed
-.Pp
-Dès que possible, donner la possibilité de lire les données d'entrée du
-programme directement sur l'entrée standard.
-Il pourra ainsi être chaîné avec un autre processus en charge, par
-exemple, de pré-traiter ses données d'entrée.
-De même, écrire les données en sortie du programme sur la sortie
-standard pour qu'un autre utilitaire puisse en post-traiter le
-résultat.
-Si plusieurs fichiers d'entrée/de sortie sont lus/écrits par le
-programme, définir les données les plus à même d'être pré/post-traitées
-pour choisir lesquelles seront lues/écriture sur l'entrée/la sortie
-standard.
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh FICHIERS
-.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.Sh VOIR AUSSI
-.Xr gcc 1 ,
-.Xr getopt 3 ,
-.Xr feature_test_macros 7
-.Pp
-.Rs
-.%A IEEE
-.%A The Open Group
-.%R Base Definitions, POSIX.1-2001
-.%T Section 12, Utility Conventions
-.Re
-.Pp
-.Rs
-.%A La Fondation pour le logiciel libre
-.%T Comment utiliser les licences GNU pour vos logiciels
-.%U https://www.gnu.org/licenses/gpl-howto.fr.html
-.Re
diff --git a/doc/fr/star-c.7.in b/doc/fr/star-c.7.in
@@ -0,0 +1,1804 @@
+.\" Copyright (C) 2026 |Méso|Star> (contact@meso-star.com)
+.\"
+.\" Ce fichier fait partie de Star-Style.
+.\"
+.\" Star-Style est un logiciel libre ; vous pouvez le redistribuer ou le
+.\" modifier suivant les termes de la GNU General Public License telle
+.\" que publiée par la Free Software Foundation ; soit la version 3 de
+.\" la licence, soit (à votre gré) toute version ultérieure.
+.\"
+.\" Star-Style est distribué dans l'espoir qu'il sera utile, mais SANS
+.\" AUCUNE GARANTIE ; sans même la garantie tacite de QUALITÉ MARCHANDE
+.\" ou d'ADÉQUATION à UN BUT PARTICULIER. Consultez la GNU General
+.\" Public License pour plus de détails.
+.\"
+.\" Vous devez avoir reçu une copie de la GNU General Public License en
+.\" même temps que Star-Style ; si ce n'est pas le cas, consultez
+.\" <http://www.gnu.org/licenses>.
+.Dd October 14, 2026
+.Dt STAR-C 7
+.Os
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh NOM
+.Nm star-c
+.Nd guide d'écriture de code en C
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh DESCRIPTION
+Ce document décrit les conventions d'écriture des programmes C
+distribués par |Méso|Star>.
+Ces recommandations sont données à titre indicatif, et reste
+subordonnées aux pratiques effectivement retenues dans chaque
+projet ; le plus important étant d'en conserver la cohérence.
+Si bien que s'il appartient aux co-auteurs d'un projet de prendre
+certaines libertés quant à ce guide de style, toute participation à son
+développement devra alors s'efforcer de respecter le style d'écriture du
+projet, avant les préférences listées ici.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LE CONTENU D'UN PROJET
+En suivant le philosophie UNIX, assurer un jeu de
+fonctionnalités par programme aussi ramassé que possible de
+sorte à ce que sa mise en oeuvre et son interface restent
+simples et ciselées.
+L'objet étant d'assurer sa robustesse, son efficacité et sa
+modularité qui dépendent d'abord de sa
+.Em relation
+à un écosystème logiciel qui le dépasse, bien avant son catalogue de
+fonctionnalités ou ses prouesses de mise en oeuvre.
+.Pp
+Le périmètre étroit de chaque programme se retrouve dès lors dans la
+structure du projet auquel il appartient, dont le contenu est alors
+simple et peu hiérarchisé car comptant en définitive peu de fichiers.
+.Pp
+La structure type du répertoire d'un projet est :
+.Bd -literal -offset Ds
+README.md
+COPYING
+config.mk
+Makefile
+src/foo.h
+src/foo.c
+src/foo_bar.c
+doc/foo_bar.1
+doc/foo.3
+.Ed
+.Pp
+Avec :
+.Bl -dash -compact
+.It
+.Pa README.md
+le fichier qui donne le premier niveau d'informations sur le projet ;
+.It
+.Pa COPYING
+la license du projet qui liste ses conditions légales d'utilisation ;
+.It
+.Pa config.mk
+et
+.Pa Makefile
+les fichiers du système de génération automatique du projet ;
+.It
+.Pa src/
+le répertoire qui contient les codes source du projet ;
+.It
+.Pa doc/
+le répertoire qui stocke sa documentation.
+.El
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LE LANGAGE C
+Utiliser le langage
+.Em C89
+.Pq ANSI X3.159-1989
+aussi appelé C90
+.Pq ISO/IEC 9899:1990 ,
+les deux étant équivalent.
+.Pp
+Cette norme est plus épurée que celle qui lui succède à savoir le C99
+.Pq ISO SO/IEC 9899:1999 ,
+ce qui en fait un dialecte C à la fois plus simple, plus portable et
+plus consistant.
+Par exemple en ne proposant qu'une seule façon d'écrire les commentaires,
+et en interdisant de mélanger du code avec la définition de variables.
+.\""""""""""""""""""""""""""""""""""
+.Ss Le standard POSIX
+Ajouter le support du standard POSIX pour les seuls fichiers qui en ont
+besoin, pour notamment pouvoir utiliser des fonctions de la bibliothèque
+C standard sinon indisponibles via la seule norme du langage retenue.
+.Pp
+Pour ce faire, définir la macro
+.Sy _POSIX_C_SOURCE
+tout en haut du fichier C concerné, avant la moindre directive
+d'inclusion.
+Par exemple, pour utiliser le standard POSIX.1-2001 :
+.Bd -literal -offset Ds
+#define _POSIX_C_SOURCE 200112L
+.Ed
+.Pp
+Sous GNU/Linux, se référer à
+.Xr feature_test_macros 7
+pour une description exhaustive des macros utilisées pour activer le jeu
+de fonctionnalités d'un standard donné.
+.Pp
+L'utilisation d'un C enrichi du standard POSIX n'est ainsi utilisé que
+sur les seuls fichiers qui en explicite le besoin ; le C89 restant le
+langage utilisé partout ailleurs.
+Dans un même souci de portabilité, retenir la première version du
+standard POSIX à partir de laquelle la fonctionnalité recherchée est
+apparue.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LA STRUCTURE D'UN FICHIER SOURCE
+Suivre une seule et même structure pour tous les fichiers
+sources, qu'ils soient des fichiers d'en-tête
+.Pq fichiers Ql *.h
+ou des unités de compilation
+.Pq fichiers Ql *.c .
+Un seul schéma de lecture participant à la clarté du code source.
+.Pp
+Ci-après sont listées les différentes parties d'un fichier source :
+.Bl -enum
+.\""""""""""""""""""""""""""""""""""
+.It
+Un commentaire avec l'avis de copyright et les avis de licence du
+programme
+.Pq section Sx L'AVIS DE COPYRIGHT ET LES AVIS DE LICENCE Ns
+ ;
+.\""""""""""""""""""""""""""""""""""
+.It
+La définition des macros qui ajoute au langage C du fichier le support
+d'un standard POSIX
+.Pq section Sx LE LANGAGE C Ns
+ ;
+.\""""""""""""""""""""""""""""""""""
+.It
+Pour un fichier d'en-tête, l'ouverture d'un garde-fou évitant sa double
+inclusion.
+Il est fermé en toute fin du fichier
+.Pq partie 10 Ns
+ :
+.Bd -literal -offset Ds
+#ifndef FOO_H
+#define FOO_H
+.Ed
+.Pp
+Le nom de la macro testée puis définie est celui du fichier d'en-tête,
+en majuscule, suffixé par
+.Ql _H
+en référence à l'extension
+.Ql .h
+du fichier.
+Dans l'exemple qui précède, le garde-fou concerne donc le fichier
+.In foo.h .
+La convention de nommage est sinon celle utilisée pour n'importe quelle
+macro
+.Pq section Sx LE NOMMAGE .
+.\""""""""""""""""""""""""""""""""""
+.It
+L'inclusion des fichiers d'en-tête requis par le fichier source ;
+.Pq section Sx LES FICHIERS D'EN-TÊTE Ns
+ ;
+.\""""""""""""""""""""""""""""""""""
+.It
+La définition des macros
+.Pq section Sx LES MACROS Ns
+ ;
+.\""""""""""""""""""""""""""""""""""
+.It
+La déclaration anticipée des types structurés :
+.Bd -literal -offset Ds
+/* Type structurés externes au programme */
+struct plugh;
+struct quux;
+struct xyzzy;
+
+/* Types structurés définis ailleurs dans le programme */
+struct bar;
+struct foo;
+.Ed
+.\""""""""""""""""""""""""""""""""""
+.It
+La définition des constantes symboliques de type
+.Vt enum
+.Pq section Sx LES CONSTANTES SYMBOLIQUES Ns
+ ;
+.\""""""""""""""""""""""""""""""""""
+.It
+La définition des types structurés et de leur(s) constante(s)
+.Pq section Sx LES STRUCTURES Ns
+ ;
+.\""""""""""""""""""""""""""""""""""
+.It
+La déclaration et définition des fonctions
+.Pq section Sx LES FONCTIONS .
+Dans l'ordre qui suit :
+.Pp
+.Bl -tag -compact -width a.
+.It a.
+la déclaration des fonctions ;
+.It b.
+la définition des fonctions statiques ;
+.It c.
+pour les unités de compilation, la définition des fonctions.
+.El
+.\""""""""""""""""""""""""""""""""""
+.It
+Pour les fichiers d'en-tête, la fin du garde-fou ouvert en 3 pour éviter
+la double inclusion du contenu du fichier.
+.El
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LA LONGUEUR DES LIGNES
+La longueur maximale recommandée pour une ligne est de
+.Em 80
+caractères.
+.Pp
+Ce nombre, standardisé par les cartes perforées et les terminaux des
+années 1970, vise aussi à faciliter la lecture du code source en
+s'insipirant des conventions d'édition.
+Pour un texte imprimé avec une taille de police entre 9 à 12 points et
+un inter-ligne d'un caractère, un confort de lecture est assuré dès
+lors que chaque ligne compte entre 60 et 75 caractères.
+Une proximité avec les 80 caractères retenus, que l'indentation
+des sources vient encore renforcer.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh L'AVIS DE COPYRIGHT ET LES AVIS DE LICENCE
+Utiliser la licence libre GPLv3+ qui, en tant que licence copyleft,
+défend la copie, l'étude et la modification libres du programme ainsi
+licencié, et de ses évolutions.
+.Pp
+Ajouter une copie de la licence à la racine du projet, dans un fichier
+texte nommé
+.Pa COPYING
+.Pq voir Lk https://www.gnu.org/licenses/gpl-3.0.txt .
+.Pp
+Lister en commentaire l'avis de copyright et la déclaration
+d'autorisation de copie en en-tête de
+.Em chaque
+fichier source.
+.Pp
+Chaque copyright débute par le mot
+.Ql Copyright ,
+en anglais, suivi des 3 caractères
+.Ql (C) ,
+traduction ASCII du caractère © qui, quant à lui, peut ne pas être
+supporté par la police de caractères utilisée.
+Lister ensuite les années pour lesquelles une version du programme a été
+publiée, avant le nom de l'auteur(e) ayant participé(e) à
+sa réalisation.
+Conclure chaque avis par l'adresse de contact de l'auteur(e), donnée
+entre parenthèses.
+.Pp
+Sauter une ligne après l'avis de copyright et ajouter la déclaration
+autorisant la copie telle que donnée par la Fondation pour le logiciel
+libre.
+Utiliser l'avis de copyright en anglais qui, au contraire de sa
+traduction française, revêt une signification juridique.
+.Pp
+L'en-tête type d'un fichier source du programme
+.Ql Foo
+est :
+.Bd -literal -offset Ds
+/* Copyright (C) 2016-2018, 2020, 2022, 2026
+ * Jeanne Lambda (jeanne.lambda@courriel.fr)
+ * Copyright (C) 2017, 2019 Jean Untel (juntel@courriel.fr)
+ * Copyright (C) 2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This file is part of Foo.
+ *
+ * Foo is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Foo is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with Foo. If not, see
+ * <https://www.gnu.org/licenses/>. */
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh L'INDENTATION
+Indenter le texte par 2 espaces.
+La mise en page du texte, taille de ligne comprise, est ce faisant
+indépendante de la taille d'une tabulation.
+.Pp
+Les auteures et auteurs sont encouragés à configurer leur éditeur de
+texture pour qu'il développe chaque caractère tabulation en 2 espaces
+.Pq section Sx FICHIERS .
+Et ainsi continuer à utiliser la touche tabulation pour l'indentation.
+.Pp
+Limiter l'indentation à 2 caractères, contre 8 pour le standard de facto
+des tabulations, laisse plus d'espace aux différents niveaux
+d'indentation, dès lors moins contraints par la limite du nombre de
+caractères par ligne
+.Pq section Sx LA LONGUEUR DES LIGNES .
+Néanmoins, un niveau d'indentation supérieur à 3 est aussi le signe d'un
+déficit de structure dans l'écriture du programme.
+Les 2 espaces retenus pour indenter le code n'est donc pas une
+incitation à aller au delà de 3 niveaux d'indentation sous prétexte de
+disposer de plus d'espace par niveau.
+.Pp
+Indenter le contenu de chaque bloc
+.Pq section Sx LES BLOCS .
+Pour la directive
+.Ql switch ,
+indenter chaque
+.Ql case
+ainsi que leur contenu :
+.Bd -literal -offset Ds
+switch (opt) {
+ case 'e':
+ errno = 0;
+ epsilon = strtod(optarg, NULL);
+ if (errno != 0) err = 1;
+ break;
+ case 'h':
+ printf("usage: foo [-hov]\en");
+ break;
+ case 'o':
+ output = optarg;
+ break;
+ case 'v':
+ verbose += (verbose < 3);
+ break;
+ default:
+ err = 1;
+ break;
+}
+.Ed
+.Pp
+Motiver l'utilisation de plusieurs instructions par ligne par
+l'expressivité du code en résultant, qu'une écriture resserrée viendrait
+renforcer :
+.Bd -literal -offset Ds
+if (x == NULL || y == NULL) { err = 1; goto error; }
+x[0] = 1.0; x[1] = 0.0;
+y[0] = 0.0; y[1] = 1.0;
+.Ed
+.Pp
+Ne sauter au plus qu'une ligne.
+Ne pas laisser d'espace en fin de ligne et supprimer les lignes vides
+en fin de fichier.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES COMMENTAIRES
+Utiliser des commentaires dès lors que la seule expressivité serrée du
+code ne permet pas d'exprimer l'entièreté du discours que les sources
+doivent rendre compte, ou la logique qu'il met effectivement en oeuvre.
+.Pp
+Ajouter un espace après l'ouverture du commentaire
+.Ql /*
+et avant sa fermeture
+.Ql */ .
+.Pp
+Si un commentaire occupe plusieurs lignes, ajouter un caractère
+.Ql *
+en début de ligne, aligné avec le caractère
+.Ql *
+de la ligne qui précède.
+Ajouter un espace entre le caractère
+.Ql * ,
+qui marque la continuation du commentaire, et la suite du commentaire :
+.Bd -literal -offset Ds
+/* Valeurs de hachage initiales, à savoir les 32 premiers bits
+ * de la partie fractionnaire des racines carrées des 4 premiers
+ * nombres premiers (2, 3, 5 et 7) */
+state[0] = 0x6a09e667;
+state[1] = 0xbb67ae85;
+state[2] = 0x3c6ef372;
+state[3] = 0xa54ff53a;
+.Ed
+.Pp
+Les commentaires servent aussi à structurer la lecture du code source.
+Que ce soit à l'échelle des instructions, par un commentaire
+.Dq chapeau
+qui résume la séquence de code qui suit :
+.Bd -literal -offset Ds
+/* Enregistrer le résultat */
+((uint32_t*)hash)[0] = big_endian_32(state[0]);
+((uint32_t*)hash)[1] = big_endian_32(state[1]);
+((uint32_t*)hash)[2] = big_endian_32(state[2]);
+((uint32_t*)hash)[3] = big_endian_32(state[3]);
+.Ed
+.Pp
+ou à l'échelle du fichier, où les commentaires servent alors de
+séparateur entre ses différentes sections
+.Pq voir Sx LA STRUCTURE D'UN FICHIER SOURCE .
+Dans ce cas, encadrer le commentaire par deux ligne de caractères
+.Ql *
+qui débute ou se termine par le caractère
+.Ql /
+si, respectivement, la ligne précède ou suit l'intitulé de la section :
+.Bd -literal -offset Ds
+/***********************************************************
+ * Définition des fonctions utilitaires
+ **********************************************************/
+static void
+foo(uint32_t bar[4], const char baz[64])
+{
+ ...
+}
+
+static int
+qux(const int xyzzy)
+{
+ ...
+}
+.Ed
+.Pp
+À noter que dans l'exemple qui précède, la taille des lignes
+d'encadrement est limitée par des contraintes d'édition de la présente
+page de manuel.
+Dans un fichier source, étendre ces lignes pour qu'elles occupent la
+longueur maximale recommandée pour une ligne
+.Pq section Sx LA LONGUEUR DES LIGNES .
+.Pp
+Pour expliciter le contexte général d'un fichier, en terme d'utilisation
+ou d'architecture logicielle, insérer un commentaire en en-tête du
+fichier en laissant les caractères d'ouverture ou de fermeture de
+commentaires sur une ligne séparée :
+.Bd -literal -offset Ds
+/*
+ * Interface de programmation des tableaux extensibles.
+ * Cette structure de données peut être utilisée avec des
+ * types de données qui ne nécessitent pas de processus
+ * d'initialisation ou de libération et qui peuvent être
+ * copiés bit à bit
+ */
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES FICHIERS D'EN-TÊTE
+Inclure les fichiers d'en-tête dans l'ordre qui suit :
+.Bl -enum -compact
+.It
+les en-têtes locaux au programme ;
+.It
+les en-têtes des dépendances du programme ;
+.It
+les en-têtes systèmes et ceux de la bibliothèque C standard.
+.El
+.Pp
+Les fichiers d'en-tête sont ainsi inclus dans l'ordre décroissant de
+leur niveau d'abstraction.
+Cet ordre participe à garantir que chaque fichier d'en-tête inclus les
+en-têtes dont il a lui même besoin, indépendamment des directives
+d'inclusion qui précèdent sa propre inclusion.
+Si ce n'est pas le cas, la compilation pourra échouer, symptôme qu'un
+des fichiers d'en-tête n'est pas auto-consistant.
+.Pp
+Dans chaque groupe, trier les directives d'inclusion par ordre
+alphabétique des fichiers d'en-tête.
+Si besoin, ajouter un commentaire court, sur la même ligne que la
+directive d'inclusion, qui explicite la raison pour laquelle la fichier
+est inclus.
+.Bd -literal -offset Ds
+#include "bar.h"
+#include "foo.h"
+#include "qux.h"
+
+#include <baz.h>
+
+#include <float.h> /* FLT_MAX */
+#include <stdio.h>
+.Ed
+.Pp
+S'efforcer de n'inclure que les seuls fichiers d'en-tête
+réellement nécessaires au fichier ;
+par exemple par une déclaration anticipée des types structurés à
+la place d'inclure des en-têtes dans le seul but de déclarer lesdits
+types.
+Un enjeu a considérer avec d'autant plus d'attention que le fichier
+concerné par les inclusions est lui même un fichier d'en-tête, par
+conséquent amené à être lui même inclus.
+L'objet étant de limiter autant que possible le nombre de fichiers
+inclus par unité de compilation, pour limiter les accès disque et ainsi
+réduire les temps de compilation.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LA VISIBILITÉ DES SYMBOLES
+Par défaut, n'exposer aucun symbole
+.Po
+option
+.Fl fvisibility=hidden
+du compilateur
+.Xr gcc 1
+.Pc ,
+à l'exception de ceux de l'interface de programmation d'une
+bibliothèque.
+.\""""""""""""""""""""""""""""""""""
+.Ss Les symboles d'interface
+Privilégier l'écriture d'un seul fichier d'en-tête pour exposer
+l'interface de programmation d'une bibliothèque.
+Y définir une macro qui exporte les symboles qu'elle déclare dès lors
+que ce fichier d'en-tête est inclus par une unité de compilation de la
+bibliothèque.
+Et qui se contente d'importer ces mêmes symboles si ce même fichier est
+inclus par un programme tiers :
+.Bd -literal -offset Ds
+#include <rsys/rsys.h>
+
+#if defined(FOO_SHARED_BUILD)
+ #define FOO_API extern EXPORT_SYM
+else
+ #define FOO_API extern IMPORT_SYM
+#endif
+.Ed
+.Pp
+Avec :
+.Bl -dash -compact
+.It
+.Sy FOO_SHARED_BUILD
+une macro définie uniquement à la compilation de la bibliothèque
+.Po
+option
+.Fl DFOO_SHARED_BUILD
+du compilateur C
+.Pc Ns
+ ;
+.It
+.Sy EXPORT_SYM
+et
+.Sy IMPORT_SYM
+des directives définies dans la bibliothèque
+.Ql RSys .
+Elles enrichissent le langage C d'une gestion explicite de la visibilité
+des symboles.
+.El
+.Pp
+Utiliser cette macro à la déclaration des variables et constantes
+d'interfaces :
+.Bd -literal -offset Ds
+/* Variables globales de l'interface de programmation */
+FOO_API const struct foo foo_plugh;
+FOO_API const struct foo foo_xyzzy;
+.Ed
+.Pp
+Déclarer le prototype des fonctions d'interface entre les directives
+.Sy BEGIN_DECLS
+et
+.Sy END_DECLS ,
+elles aussi définies dans la bibliothèque
+.Ql RSys
+.Pq en-tête In rsys/rsys.h .
+Ainsi, le fichier d'en-tête peut être inclus par un programe C++ :
+.Bd -literal -offset Ds
+BEGIN_DECLS
+
+FOO_API void
+foo_bar
+ (int i,
+ int* j);
+
+FOO_API int
+foo_qux
+ (double d,
+ int i);
+
+END_DECLS
+.Ed
+.\""""""""""""""""""""""""""""""""""
+.Ss Les symboles internes partagés
+Pour les fichiers d'en-tête internes au programme, utiliser la directive
+.Sy LOCAL_SYM ,
+définie dans le fichier
+.In rsys/rsys.h
+de la bibliothèque
+.Ql RSys ,
+pour déclarer les variables globales et prototypes de fonctions.
+Ainsi leur symbole n'est pas exposé à l'extérieur du programme.
+.Bd -literal -offset Ds
+#include <rsys/rsys.h>
+
+extern LOCAL_SYM char bar[128];
+
+extern LOCAL_SYM void
+quux
+ (char* tab,
+ size_t length);
+.Ed
+.Pp
+Cette directive est redondante si le compilateur est configuré pour
+masquer par défaut tous les symboles
+.Po
+option
+.Fl fvisibility=hidden
+de
+.Xr gcc 1
+.Pc .
+Utiliser
+.Sy LOCAL_SYM
+permet néanmoins de s'exonérer de cet a priori, tout en uniformisant
+les déclarations des fonctions et variables en explicitant pour chaque
+déclaration la visibilité du symbole associé.
+.\""""""""""""""""""""""""""""""""""
+.Ss Les symboles internes à une unité de compilation
+Utiliser le mot clé
+.Ql static
+pour déclarer des variables, constantes, et fonctions visibles
+uniquement au sein d'une unité de compilation.
+.Pp
+C'est notamment le cas des constantes symboliques structurées :
+.Bd -literal -offset Ds
+struct foo {
+ int bar;
+ int qux;
+};
+static const struct foo FOO_DEFAULT = {1, 0};
+.Ed
+.Pp
+Mais aussi des fonctions utilitaires, qu'elles soient
+propres à un fichier C, ou définies dans un fichier d'en-tête.
+.Bd -literal -offset Ds
+static void
+hello(void)
+{
+ printf("Hello, world!\en");
+}
+.Ed
+.Pp
+Ces fonctions peuvent en plus être déclarées avec la directive
+.Sy INLINE ,
+définie dans l'en-tête
+.In rsys/rsys.h
+de la bibliothèque
+.Ql RSys ,
+pour suggérer au compilateur de substituer l'appel de la fonction par le
+corps de celle-ci, de sorte à éviter le surcoût de l'appel.
+Cette directive est équivalente au mot clé
+.Ql inline
+du C99, indisponible dans le dialecte C retenu
+.Pq section Sx LE LANGAGE C .
+.Bd -literal -offset Ds
+static INLINE void
+foo(void)
+{
+ printf("bar\en");
+}
+.Ed
+.Pp
+Limiter la directive
+.Sy INLINE
+aux fonctions élémentaires, destinées à être appelées fréquemment et
+dont le coût de l'appel pourrait alors s'avérer significatif.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES BLOCS
+Ouvrir chaque bloc sur la même ligne que la directive qui en est à
+l'origine
+.Po
+.Ql do ,
+.Ql enum
+.Ql for ,
+.Ql if ,
+.Ql struct ,
+.Ql switch ,
+.Ql union ,
+.Ql while
+.Pc ,
+en séparant par un espace la fin de la directive et le caractère
+.Ql {
+qui marque l'ouverture du bloc :
+.Bd -literal -offset Ds
+if (foo) {
+ bar();
+ qux();
+}
+.Ed
+.Pp
+Exception faite des fonctions, ou le bloc associé est ouvert sur la
+ligne qui suit :
+.Bd -literal -offset Ds
+static void
+foo(void)
+{
+ printf("bar\en");
+}
+.Ed
+.Pp
+Fermer un bloc sur une ligne à part sauf s'il est suivi d'une nouvelle
+structure de contrôle associée à la précédente
+.Po
+.Ql if else ,
+.Ql do while
+.Pc .
+Dans ce cas, ajouter la nouvelle instruction sur la même ligne que celle
+utilisée pour fermer le bloc, en la séparant du caractère
+.Ql }
+par un espace.
+.Pp
+Aligner la fermeture du bloc à l'indentation de sa directive, ou, dans
+le cas de directives qui se suivent, à l'indentation de la première
+directive à l'origine des blocs successifs :
+.Bd -literal -offset Ds
+if (foo) {
+ bar();
+} else {
+ qux();
+}
+.Ed
+.Pp
+Écrire sur une seule ligne une directive et les opérations qu'elle
+contrôle que si la clarté du code n'en est pas impactée.
+Dans ce cas, l'ouverture et la fermeture du bloc associé se fait sur une
+seule et même ligne :
+.Bd -literal -offset Ds
+if (foo) { bar(); return 0; }
+.Ed
+.Pp
+Ne pas utiliser d'accolades si la structure de contrôle n'est suivie
+d'aucune ou d'une seule directive écrite sur la même ligne :
+.Bd -literal -offset Ds
+while (foo());
+
+if (bar) return 0;
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES MOTS CLÉS
+Ajouter un espace après chaque structure de contrôle
+.Ql if ,
+.Ql switch ,
+.Ql for
+et
+.Ql while
+pour les différencier des appels de fonctions.
+Ne pas ajouter d'espace après l'ouverture et avant la fermeture des
+parenthèses qui détourent leur(s) expression(s) :
+.Bd -literal -offset Ds
+if (i < 10) {
+ foo(i);
+}
+.Ed
+.Pp
+Ajouter un espace après chaque point virgule qui sépare les expressions
+d'une boucle
+.Ql for
+sauf si l'expression qui suit est vide :
+.Bd -literal -offset Ds
+for (i=0; i<10; foo(i++));
+
+for (;;) { /* Boucle infinie */
+ poll();
+ if(bar) break;
+}
+.Ed
+.Pp
+Assimiler l'instruction
+.Ql sizeof
+à une fonction ; ne pas insérer d'espace entre le mot clé et son
+expression entourée de parenthèses :
+.Bd -literal -offset Ds
+sz = sizeof(int);
+.Ed
+.\""""""""""""""""""""""""""""""""""
+.Ss L'instruction Ql switch
+Limiter à quelques lignes le contenu de chaque
+.Ql case
+d'une instruction
+.Ql switch ,
+celle-ci devant donner à lire la seule répartition des traitements,
+fonction de la valeur que peut prendre l'expression du
+.Ql switch .
+Et non les traitements eux même, sauf s'ils sont triviaux.
+Un
+.Ql case
+au contenu trop fourni est alors le signe d'un manque de structure dans
+l'écriture du programme.
+.Pp
+Toujours ajouter une instruction
+.Ql default
+même si l'ensemble des valeurs que pourraient prendre l'expression du
+.Ql switch
+est censé être couvert par les différents
+.Ql case .
+C'est notamment le cas quand l'expression est une variable
+d'énumération.
+Utiliser alors la directive
+.Sy FATAL ,
+définie par la bibliothèque
+.Ql RSys
+.Pq en-tête In rsys/rsys.h ,
+pour signifier un comportement inattendu.
+Et ainsi pouvoir diagnostiquer une erreur dans la valeur de l'expression
+du
+.Ql switch ,
+ou un
+.Ql case
+manquant :
+.Bd -literal -offset Ds
+switch (i) {
+ case FOO: foo(); break;
+ case BAR: bar(); break;
+ case QUX: qux = 1; break;
+ default: FATAL("Unreachable code\en"); break;
+}
+.Ed
+.Pp
+Ajouter la directive
+.Sy FALLTHROUGH ,
+définie dans le fichier d'en-tête
+.In rsys/rsys.h
+de la bibliothèque
+.Ql RSys ,
+en fin des instructions
+.Ql case
+qui s'enchaînent.
+L'ajout de cette directive permet d'expliciter que c'est bien le
+comportement attendu et non l'oublie d'une instruction
+.Ql break ,
+en plus d'éviter un possible message d'avertissement à la compilation
+.Pq option Fl Wimplicit-fallthrough No de Xr gcc 1 Ns
+ :
+.Bd -literal -offset Ds
+switch (c) {
+ case 'a':
+ foo = 1;
+ FALLTHROUGH;
+ case 'b':
+ bar = 1;
+ break;
+ default:
+ usage();
+ break;
+}
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LE NOMMAGE
+.\""""""""""""""""""""""""""""""""""
+.Ss Les variables
+Nommer les variables en minuscules.
+Utiliser le tiret bas
+.Ql _
+au titre de séparateur entre les termes utilisés dans le nom des
+variables :
+.Bd -literal -offset Ds
+foo_bar
+.Ed
+.Pp
+Expliciter l'objet d'une variable dans son nom avec d'autant plus de
+précision que sa portée est grande.
+Une variable locale à un bloc de quelques lignes pourra se contenter
+d'un nom abrégé tel que
+.Va tmp
+pour un résultat temporaire, voire n'être qu'un seul caractère
+pour un indice
+.Va i
+ou un nombre d'éléments
+.Va n Ns
+ ; leur contexte d'utilisation venant préciser ce que leur nom résume.
+Ce nom abrégé vient non seulement alléger l'écriture mais aussi en
+renforcer l'expressivité.
+Par exemple
+.Va tableau Ns Bq Va i
+reste plus clair que
+.Va tableau Ns Bq Va indice .
+.Pp
+Les variables globales sont au contraire à nommer de sorte à décrire ce
+qu'elles représentent, indépendamment de tout contexte d'utilisation,
+par construction distant de leur déclaration.
+Un compteur d'allocations global à un programme aura donc pour nom
+.Va compteur_allocations
+plutôt que
+.Va cpt_allocs .
+.Pp
+Pour une variable globale déclarée au niveau de l'interface d'une
+bibliothèque, préfixer ladite variable avec l'acronyme de la
+bibliothèque.
+Un compteur d'allocation global à la bibliothèque
+.Ql Foo ,
+et déclaré en tant que variable globale de son interface, sera alors
+nommé
+.Va foo_compteur_allocations .
+.\""""""""""""""""""""""""""""""""""
+.Ss Les fonctions
+Nommer les fonctions avec des caractères alphanumérique en minuscules,
+et séparer les termes qui composent leur nom par un tiret bas
+.Pq caractère Ql _ .
+.Pp
+Donner à une fonction un nom d'autant plus explicite que sa portée est
+importante.
+Une fonction utilitaire pourra se contenter d'un nom abrégé, tel que
+.Fn cmp
+pour une fonction de comparaison utilisée comme argument d'un appel à
+.Xr qsort 3
+au sein d'un fichier C.
+Là où une fonction partagée entre plusieurs unités de compilation aura
+un nom plus expressif, tel que
+.Fn compare_bar ,
+pour notamment expliciter le type
+.Vt struct bar
+des variables comparées.
+Jusqu'à préfixer le nom de la fonction par l'acronyme de la bibliothèque
+quand elle est une fonction d'interface de ladite bibliothèque.
+Pour la bibliothèque
+.Ql Foo ,
+une fonction d'interface sera alors nommée
+.Fn foo_compare_bar .
+.\""""""""""""""""""""""""""""""""""
+.Ss Les déclarations de types
+Utiliser des caractères alphanumériques en minuscules pour nommer les
+structures, unions et énumérations.
+Utiliser le tiret bas
+.Ql _
+pour séparer les différents termes qui composent leur nom.
+.Bd -literal -offset Ds
+struct foo {
+ int bar;
+ int baz
+};
+
+union foo_bar {
+ double qux;
+ int xyzzy;
+};
+.Ed
+.Pp
+Utiliser la même convention pour nommer les déclarations typedef.
+À l'exception du suffixe
+.Ql _T
+ajouté au nom de l'identificateur du type, en écho au suffixe
+.Ql _t
+souvent utilisé pour ce type de déclaration, mais réservé par le
+standard POSIX.
+.Bd -literal -offset Ds
+typedef int foo_T;
+typedef char foo_bar_T[256];
+.Ed
+.Pp
+Ne pas utiliser de déclaration typedef sur les structures, unions et
+énumérations de sorte à permettre leur déclaration anticipée.
+.Pp
+Préfixer le nom d'un type par l'acronyme de la bibliothèque dès lors
+qu'il est un type déclaré en tant que type de son interface.
+Par exemple, un type structuré de l'interface de la bibliothèque
+.Ql Foo
+sera nommé
+.Vt struct foo_mon_type .
+.\""""""""""""""""""""""""""""""""""
+.Ss Constantes et macros
+Utiliser des majuscules pour nommer les constantes symboliques, qu'elles
+soient des macros, des constantes énumérées, ou des variables déclarées
+comme constantes.
+Séparer par un tiret bas
+.Ql _
+les termes qui composent leur nom :
+.Bd -literal -offset Ds
+#define FOO_BAR 42
+
+enum foo {
+ BAR_BAZ,
+ QUX
+};
+
+static const enum foo FOO_XYZZY = BAR_BAZ;
+.Ed
+.Pp
+Nommer une constante ou une macro de manière d'autant plus explicite
+que sa portée est importante.
+Une constante définie localement à une fonction pourra se contenter
+d'un nom abrégé, jusqu'à n'être qu'un seul caractère, par exemple pour
+un nombre d'éléments constant
+.Sy N .
+Là où le nom d'une macro ou d'une constante définie dans un fichier
+d'en-tête se devra d'être plus explicite, tel que
+.Sy NOMBRE_ELEMENTS_MAX .
+Et être préfixée par l'acronyme de la bibliothèque si elle est déclarée
+comme macro ou constante de son interface.
+Par exemple, pour la bibliothèque
+.Ql Foo ,
+.Sy FOO_NOMBRE_ELEMENTS_MAX .
+.Pp
+Utiliser la convention typographique dite
+.Dq camel case
+pour nommer les arguments des macros ;
+les termes qui composent leur nom sont séparés par une variation de la
+casse typographique.
+Un terme débute par une majuscule, suivi de caractères
+alphanumériques en minuscules.
+.Bd -literal -offset Ds
+#define FOO_BAR(FooBar, Qux) ((FooBar) + (Qux))
+.Ed
+.Pp
+Ainsi, les arguments de macros sont différenciés des constantes
+symboliques et des variables.
+.Pp
+À noter que la macro elle même est nommée selon la même convention que
+celle utilisée pour les constante symboliques
+.Pq en majuscule et un tiret bas pour séparer ses différents termes .
+La parenthèse ouvrante, collée au nom de la macro, permettant de
+différencier les 2 cas.
+.\""""""""""""""""""""""""""""""""""
+.Ss Les variables et macros internes
+Suffixer par deux tirets bas
+.Ql __
+les variables membres d'une structure définie publiquement, qui n'ont
+cependant une signification qu'en interne des fonctions d'interface de
+la structure.
+L'enjeu étant de souligner que ces variables ne sont accessibles que par
+effet de bord, et ne s'addressent
+.Em pas
+aux utilisatrices et utilisateurs, qui ne devraient donc pas y accéder
+directement :
+.Bd -literal -offset Ds
+struct foo {
+ double bar;
+ int baz;
+ int* qux__; /* Variable interne */
+};
+.Ed
+.Pp
+Utiliser le même suffixe en double tirets bas
+.Ql __
+pour nommer les variables internes à une macro, afin d'éviter de masquer
+les variables définies dans le contexte où la macro est développée :
+.Bd -literal -offset Ds
+#define FOO(Bar, N) { \e
+ int i__; \e
+ for (i__ = 0; i__ < N; Bar(i__), ++i__); \e
+} (void)0
+.Ed
+.Pp
+Suffixer les macros d'un fichier d'en-tête par deux tirets bas
+.Ql __
+dès lors qu'elles sont propres au fichier d'en-tête, et donc
+vraisemblablement inacessibles au delà :
+.Bd -literal -offset Ds
+#define FOO__(Type, Dim) \e
+ struct Type { \e
+ int i[Dim]; \e
+ float f[Dim]; \e
+ }
+FOO__(bar, 2);
+FOO__(baz, 3);
+FOO__(qux, 4);
+#undef FOO__
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES FONCTIONS
+S'attacher à ce que chaque fonction reste simple et concise, en ne
+s'appliquant à ne lui faire faire qu'une seule chose.
+Ce faisant, le corps d'une fonction devrait être lisible sur un ou deux
+écran, avec comme référence la taille des terminaux telle que
+démocratisée à la fin des années 1970, à savoir 24 lignes.
+.Pp
+Un indice quant à la taille qu'une fonction devrait s'efforcer à avoir
+est donné par ses niveaux d'indentation.
+Plus elle compte de niveaux et plus elle devrait être ramassée.
+De même, un nombre de variables locales supérieur à dix peut être le
+signe d'une fonction trop dense.
+.Pp
+Écrire les directives qui contrôlent la portée d'une fonction et son
+type de retour sur une ligne séparée de son nom.
+L'expression régulière
+.Ql ^nom_de_fonction
+peut ainsi être utilisée pour la recherche d'une fonction dans les
+différents fichiers sources.
+.Pp
+Pour une déclaration, revenir à la ligne avant d'ouvrir la parenthèse de
+la fonction, précédée d'une indentation par rapport au nom de la
+fonction sur la ligne qui précède.
+Puis, lister les arguments de la fonction, en revenant à la ligne après
+chacun d'eux et en les alignant les uns par rapport aux autres.
+Ajouter la parenthèse fermante
+.Ql \&)
+et le point virgule
+.Ql \&;
+sur la ligne du dernier argument, sans espace supplémentaire :
+.Bd -literal -offset Ds
+extern LOCAL_SYM void
+foo_bar
+ (struct foo* foo,
+ const int qux,
+ const float xyzzy);
+.Ed
+.Pp
+Les différentes parties qui composent le profil de la fonction sont
+ainsi identifiables par la seule mise en page de sa déclaration.
+.Pp
+Lors de sa définition, lister les arguments de la fonction sur la même
+ligne que le nom de la fonction, sans ajouter d'espace entre le nom de
+la fonction et sa parenthèse ouvrante :
+.Bd -literal -offset Ds
+void
+foo_bar(struct foo* foo, const int qux, const float xyzzy)
+{
+ ...
+}
+.Ed
+.Pp
+Si la liste des arguments dépasse la longueur maximale d'une ligne
+.Pq section Sx LA LONGUEUR DES LIGNES
+les lister comme pour une déclaration.
+.Pp
+Ordonner les arguments d'une fonction comme suit :
+.Bl -enum -compact
+.It
+pour une fonction d'interface, la variable sur laquelle la fonction
+opère ;
+.It
+les données d'entrées ;
+.It
+les données en sortie.
+.El
+.Pp
+Ajouter l'instruction
+.Ql const
+aux variables qui n'ont pas vocation à être modifiées par la fonction.
+Et ce quand bien même leur modification n'aurait aucune conséquence,
+comme pour les variables de données simples, copiées à l'appel de la
+fonction.
+L'objet étant de souligner qu'elles sont des variables en entrée :
+.Bd -literal -offset Ds
+static void
+foo
+ (struct foo* foo,
+ constr struct bar* bar,
+ const int longueur,
+ const int* liste,
+ int* resultat);
+
+static INLINE double
+madd(const double a, const double b, const double c)
+{
+ return a*b + c;
+}
+.Ed
+.Pp
+Ne passer en copie que les seuls paramètres en entrée de la fonction de
+type primitif
+.Pq Vt char , int , double , No énumération, ... .
+Utiliser un pointeur constant dès lors que le paramètre d'entrée est
+de type structuré, afin d'éviter le surcoût de sa copie à chaque appel de
+fonction ; son occupation mémoire étant a priori plus important
+qu'une donnée simple.
+.Pp
+Les paramètres d'une fonction peuvent ne pas être utilisés à l'intérieur
+de celle-ci.
+C'est notamment le cas si les paramètres ne sont utiles que pour
+répondre à un profil de fonction spécifique ou dans un contexte de
+compilation particulier, par exemple pour le débogage.
+Lister ces paramètres en en-tête de la fonction, après
+la définition des variables locales, en les préfixant d'une conversion
+explicite vers un type vide :
+.Bd -literal -offset Ds
+static void
+foo(int x, int y, int z)
+{
+ int i = 0;
+ (void)y, (void)z; /* Paramètres inutilisés */
+
+ i = bar(x);
+ if (i < 42) {
+ printf("Foobar\en");
+ }
+}
+.Ed
+.Pp
+Cette conversion explicite quels paramètres sont ignorés, en plus de
+désactiver les avertissements de compilation quant à la définition de
+paramètres non utilisés
+.Pq option Fl Wunused-parameter No de Xr gcc 1 .
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES VARIABLES
+Limiter le nombre de variables par bloc entre 5 et 10.
+Un nombre de variables trop important peut être le signe d'un manque de
+structure auquel un découpage en sous-fonction(s) pourrait remédier
+.Pq section Sx LES FONCTIONS .
+.Pp
+Initialiser les variables dès leur définition avec sinon une valeur
+valide, au moins une valeur par défaut.
+L'objet étant d'éviter l'utilisation de variables non initialisées.
+D'apparence peu critique pour les variables de type primitif, cette
+initialisation l'est bien plus pour les variables structurées, dont la
+liste des membres peut changer.
+Si elle existe, utiliser la constante proposée avec la définition du
+type structuré pour initialiser ses membres
+.Pq voir section Sx LES STRUCTURES .
+En son absence, n'initialiser que le premier membre de la variable ; le
+language C assure alors que les autres membres seront initialisés à
+zéro.
+De même pour un tableau alloué sur la pile, initialiser son premier
+élément suffit à garantir que le reste du tableau sera initialisé à
+zero :
+.Bd -literal -offset Ds
+struct foo foo = FOO_DEFAULT;
+struct bar bar = {0};
+int qux[10] = {0};
+int i = 0;
+.Ed
+.Pp
+Au sein d'une même fonction, définir les variables au plus proche de
+leur utilisation de sorte à ce que le contexte dans lequel elles sont
+utilisées participe à les caractériser.
+Par exemple, une variable
+.Va i
+utilisée dans un bloc comme variable temporaire, et comme indice de
+boucle dans un autre, gagnera en expressivité et en robustesse à être
+définie localement à chaque bloc ;
+les deux variables étant alors, par construction, non seulement séparées
+mais aussi sans effet de bord de l'une sur l'autre :
+.Bd -literal -offset Ds
+if(foo) {
+ const int i = bar();
+ if (i > max_i) max_val = i;
+ if (i < min_i) min_val = i;
+} else {
+ int i = 0;
+ for(i = 0; i < N; ++i) qux(i);
+}
+.Ed
+.Pp
+Regrouper les définitions des variables dès lors qu'elles sont liées
+sémantiquements.
+Les trier ensuite par taille mémoire décroissante, et enfin par ordre
+alphabétique :
+.Bd -literal -offset Ds
+/* Bibliothèque Foo */
+struct foo_args foo_args = FOO_ARGS_DEFAULT;
+struct foo* foo = NULL;
+
+/* Tableau à traiter */
+double* liste = NULL;
+int capacite = 0;
+int longueur = 0;
+.Ed
+.Pp
+Trier la définition des variables par taille mémoire tend à limiter le
+nombre d'octets de remplissage que le compilateur C ajoute pour garantir
+l'alignement mémoire de chaque variable eu égard à leur type.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES CONSTANTES
+Utiliser une énumération si les constantes à définir sont liées
+sémantiquement, et une macro sinon :
+.Bd -literal -offset Ds
+#define ID_INVALIDE ((unsigned)-1)
+
+enum { X, Y, Z };
+
+enum attribut {
+ POSITION,
+ NORMALE,
+ TEXCOORD
+};
+.Ed
+.Pp
+Pour une énumération qui utilise des valeurs par défaut,
+ajouter si besoin une dernière constante qui définit le nombre de
+constantes valides ;
+sa valeur sera ainsi automatiquement mise à jour à chaque changement de
+l'énumération.
+Une telle constante peut alors servir à définir la cardinalité d'un
+tableau, comme valeur du dernier indice marquant la fin d'une itération,
+ou encore comme valeur vis à vis de laquelle la validité d'une variable
+du type énuméré peut être vérifiée :
+.Bd -literal -offset Ds
+enum molecule {
+ CH4,
+ CO,
+ CO2,
+ H2O,
+ N2O,
+ O3,
+
+ NOMBRE_DE_MOLECULES
+};
+
+/* Vérifier qu'une constante définie une molecule valide */
+#define MOLECULE_EST_VALIDE(Mol) \e
+ ((unsigned)(Mol) < NOMBRE_DE_MOLECULES)
+
+static const char* NOM_DES_MOLECULES[NOMBRE_DE_MOLECULES] = {
+ "CH4", "CO", "CO2", "H2O", "N2O", "O3"
+};
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES STRUCTURES
+Définir les structures en en-tête de fichier
+.Pq section Sx LA STRUCTURE D'UN FICHIER SOURCE ,
+à l'exeption des structures locales à une fonction.
+.Pp
+Lister les variables membres d'une structure suivant la même convention
+que pour la définition des variables d'un bloc
+.Pq section Sx LES VARIABLES Ns
+ :
+les regrouper d'abord par sémantique, puis les trier par occupation
+mémoire décroissante, et enfin par ordre alphabétique.
+.Pp
+Ne définir qu'une variable membre par ligne.
+.Pp
+Pour une structure dont aucune fonction ne permet d'en initialiser les
+membres, définir une constante qui fixe leur valeur par défaut.
+Suffixer cette constante par
+.Ql DEFAULT
+ou
+.Ql NULL
+fonction de si une variable structurée ainsi initialisée est une donnée
+valide ou non.
+Déclarer cette constante en tant que variable statique et l'initialiser par
+une macro de même nom, différenciée de la variable constante par un
+double tiret bas final
+.Ql __ Ns
+ :
+.Bd -literal -offset Ds
+struct arg {
+ char* fichier; /* NULL <=> entrée standard */
+ int verbosite;
+};
+#define ARG_DEFAULT__ {NULL, 0}
+static const struct arg ARG_DEFAULT = ARG_DEFAULT__;
+
+struct chaine {
+ char* mem;
+ int longueur;
+ int capacite;
+};
+#define CHAINE_NULL__ {NULL,0,0}
+static const struct chaine CHAINE_NULL = CHAINE_NULL__;
+.Ed
+.Pp
+N'utiliser la macro que lorsqu'il est impossible d'utiliser la variable
+constante, en l'occurence pour initialiser, dès sa définition, les
+membres d'une autre variable structurée :
+.Bd -literal -offset Ds
+struct qux {
+ struct chaine foo;
+ int bar;
+};
+#define QUX_DEFAULT__ {CHAINE_NULL__, 0}
+static const struct qux QUX_DEFAULT = QUX_DEFAULT__;
+.Ed
+.Pp
+Éviter d'utiliser une déclaration typedef des structures afin
+d'autoriser leur déclaration anticipée.
+Et l'utilisation de pointeur vers une donnée structurée sans avoir sa
+définition.
+Si un déclaration typedef est néanmoins souhaitée, nommer le type
+structuré en suivant la convention de nommage des déclarations typedef
+.Pq section Sx Les déclarations de types .
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES MACROS
+Pour définir une séquence d'instructions,
+préférer l'utilisation de fonctions aux macros.
+Déclarer la fonction avec la directive
+.Sy INLINE
+si son coût d'appel est un enjeu
+.Pq section Sx Les symboles internes à une unité de compilation .
+.Pp
+Regrouper la séquence d'instructions d'une macro dans un bloc terminé
+par l'instruction
+.Ql (void)0 .
+Elle peut ainsi être utilisée comme unique expression d'une structure de
+contrôle, et force l'ajout d'un point virgule
+.Ql \&;
+.Pq ou d'une virgule Ql \&,
+après son utilisation, telle n'importe quelle autre instruction C.
+.Pp
+En C, il est plus courant d'encapsuler les instructions d'une macro
+dans une structure de contrôle
+.Ql do { ... } while (0)
+plutôt que dans un bloc terminé par la converstion de l'entier zéro vers
+un type vide
+.Ql (void)0 .
+Si les deux écritures répondent aux mêmes objectifs, cette dernière
+convention évite les avertissements émis par certains compilateurs quant
+à l'utilisation d'une expression conditionnelle constante dans
+.Ql while (0) .
+.Pp
+Ouvrir le bloc sur la même ligne que le nom de la macro, en ajoutant un
+espace avant l'acolade
+.Ql { .
+Indenter le contenu du bloc par rapport à la directive de définition de
+la macro.
+Justifer à droite les caractères anti-slash
+.Ql \e
+en fin de chaque ligne de sorte à faciliter la lecture de la séquence
+d'instructions développée par la macro :
+.Bd -literal -offset Ds
+#define FOO(X, Y) { \e
+ if ((X) == (Y)) printf("Bar \en"); \e
+ (Y) += 2; \e
+} (void)0
+.Ed
+.Pp
+À noter que dans l'exemple qui précède, les caractères anti-slash
+.Ql \e
+sont alignés en suivant des contraintes d'édition propres à ce manuel.
+Dans un fichier source, positioner l'anti-slash en tant que dernier
+caractère de lignes qui occupent la longueur maximale autorisée
+.Pq section Sx LA LONGUEUR DES LIGNES .
+.Pp
+Pour une macro dont la portée est l'unité de compilation, ne pas changer
+le déroulé des instructions de son contexte d'appel, par exemple en
+intégrant une directive
+.Ql return .
+Son utilisation contredirait l'exécution séquentielle du code et ce
+faisant nuirait à sa lisibilité.
+Il n'est donc
+.Em pas
+recommandé de définir une macro comme suit :
+.Bd -literal -offset Ds
+#define FOO(X) {
+ if (bar(X))
+ return -1;
+} (void)0
+.Ed
+.Pp
+Ne pas présupposer l'existance de variables externes à la macro,
+exeption faite des variables globales.
+L'objet étant de ne pas lier son bon fonctionnement au contexte local
+dans lequel elle est développée.
+L'écriture qui suit est donc
+.Em découragée Ns
+ :
+.Bd -literal -offset Ds
+#define BAR(X,Y) {
+ z = (X) + (Y);
+ if (xyzzy(z))
+ z += 1;
+}
+.Ed
+.Pp
+Contrairement aux macros définies à l'échelle d'une unité de
+compilation, une macro locale peut non seulement changer le fil
+d'exécution du contexte d'appel, mais aussi utiliser des variables
+externes.
+Et ce précisément en raison de son caractère local, qui lie étroitement
+la macro à son seul contexte d'utilisation.
+.Bd -literal -offset Ds
+static int
+foo(const int x)
+{
+ char s[10] = {0};
+ int line = 0;
+ int err = 0;
+
+ #define CALL(Func) { \e
+ if((err=(Func)) != 0) { \e
+ line = __LINE__; \e
+ goto error; \e
+ } \e
+ } (void)0
+
+ CALL(bar(x, s));
+ CALL(quux(s));
+
+ #undef CALL
+
+exit:
+ return err;
+error:
+ fprinf(stderr, "erreur %d ligne %d\en", err, line);
+ goto exit;
+}
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES ALLOCATIONS DYNAMIQUES
+Préférer l'interface d'allocation proposée par la
+bibliothèque
+.Ql RSys
+via son fichier d'en-tête
+.In rsys/mem_allocator.h .
+Elle enrichit la gestion de la mémoire dynamique proposée par la
+bibliothèque C standard, notamment en enregistrant la quantité de
+mémoire allouée.
+.Pp
+Utiliser dès lors les fonctions
+.Fn mem_alloc ,
+.Fn mem_calloc
+et
+.Fn mem_realloc
+pour allouer dynamiquement de la mémoire.
+Leur profil est celui des fonctions équivalentes proposées par la
+bibliothèque C, à savoir ces mêmes fonctions mais sans le prefixe
+.Ql mem_
+.Po
+voir
+.Xr alloc 3 ,
+.Xr calloc 3 ,
+et
+.Xr realloc 3
+.Pc .
+.Pp
+Privilégier la fonction
+.Fn mem_calloc
+à
+.Fn mem_alloc
+de sorte à initialiser la mémoire allouée à zéro, et d'éviter ainsi
+d'utiliser des données non initialisées.
+.Pp
+Ne pas convertir le pointeur retourné par les fonctions d'allocation.
+La conversion d'un pointeur vide vers n'importe quel autre type de
+pointeur est déjà assuré par le langage C.
+.Pp
+Définir la taille du bloc mémoire à allouer via le type pointé par la
+variable destination :
+.Bd -literal -offset Ds
+p = mem_calloc(42, sizeof(*p));
+.Ed
+.Pp
+L'alternative qui consiste à épeller le type pointé en argument de
+.Ql sizeof
+non seulement nuit à la lisibilité des sources, mais laisse en plus
+l'opportunité d'introduire un bogue dès lors que le type de pointeur
+est mis à jour mais pas le nom du type renseigné à
+.Ql sizeof .
+.Pp
+Utiliser la fonction
+.Fn mem_alloc_aligned
+pour allouer un bloc mémoire dont l'adresse doit être alignée sur un
+nombre d'octets spécifique.
+Utiliser la fonction
+.Xr memset 3 ,
+de la bibliothèque C standard, pour forcer la mise à zéro du bloc ainsi
+alloué sinon rempli d'octets
+aléatoires :
+.Bd -literal -offset Ds
+foo = mem_alloc_aligned(sizeof(*foo), 128/* Alignement */);
+memset(foo, 0, sizeof(*foo));
+.Ed
+.Pp
+Vérifier chaque allocation en testant que l'adresse retournée n'est pas
+.Ql NULL .
+Traiter ce cas comme une erreur et non un bogue
+.Pq section Sx CENTRALISER LA SORTIE D'UNE FONCTION Ns
+ :
+.Bd -literal -offset Ds
+ foo = mem_calloc(1, sizeof(*foo);
+ if (!foo) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+.Ed
+.Pp
+Libérer la mémoire allouée via
+.Ql RSys
+avec la fonction
+.Fn mem_rm
+dont le profil est le même que celui de la fonction
+.Xr free 3 Ns
+ :
+.Bd -literal -offset Ds
+mem_rm(foo);
+.Ed
+.Pp
+Détecter la présence de fuites mémoires via la fonction
+.Fn mem_allocated_size
+qui retourne la quantité de mémoire qui reste allouée par la
+bibliothèque :
+.Bd -literal -offset Ds
+int
+main(void)
+{
+ size_t sz = 0;
+ int err = 0;
+
+ ...
+
+ if ((sz = mem_alloc_aligned()) != 0) {
+ fprintf(stderr, "Fuites mémoires : %lu octets\en", sz);
+ if (err == 0) err = 1;
+ }
+ return err;
+}
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Ss Les allocateurs mémoire
+Dans son fichier d'en-tête
+.In rsys/mem_allocator.h ,
+la bibliothèque
+.Ql RSys
+définit en plus une interface d'allocateur mémoire.
+Au contraire de son interface d'allocation qui enregistre la mémoire
+alloué globalement par la bibliothèque,
+chaque allocateur enregistre ses seules allocations.
+.Pp
+Plusieurs types d'allocateurs sont proposés par la bibliothèque
+.Ql RSys ,
+chacun mettant en oeuvre une politique d'allocation qui lui est propre.
+Si bien qu'en fonction du contexte, un type d'allocateur particulier
+peut s'avérer plus approprié, par exemple pour réduire les coûts
+d'allocations/désallocations.
+Décrire les différents types d'allocateurs définis dans la bibliothèque
+.Ql RSys
+sort du cadre de cette documentation.
+Le lecteur est invité à se référer à son fichier d'en-tête
+.In rsys/mem_allocator.h
+pour plus d'informations.
+.Pp
+Les convention listées précédemment quant aux allocation dynamiques
+s'appliquent à l'identique à l'utilisation des allocateurs.
+.Pp
+Utiliser un allocateur consiste à appeler des macros, dont le nom est
+une version en majuscule des fonctions de l'interface d'allocation.
+Avec en plus en premier argument l'addresse de l'allocateur concerné :
+.Bd -literal -offset Ds
+foo = MEM_CALLOC(&mem_default_allocator, 1, sizeof(*foo));
+
+\&...
+
+MEM_RM(&mem_default_allocator, foo);
+
+if (MEM_ALLOCATED_SIZE(&mem_default_allocator)) {
+ fprintf(stderr, "Fuites mémoires\en");
+}
+.Ed
+.Pp
+avec
+.Va mem_default_allocator
+l'allocateur par défaut définit par la bibliothèque
+.Ql RSys .
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh CENTRALISER LA SORTIE D'UNE FONCTION
+Utiliser la directive
+.Ql goto
+pour centraliser les traitements à effectuer en sortie de fonction, tels
+les affectations de variables de sorties, les libérations de variables
+locales temporaires, ou le renvoie d'une valeur en retour de la fonction.
+Regrouper ces traitements en fin de fonction sous le label
+.Ql exit
+dont la dernière instruction est la valeur retournée par la fonction.
+.Pp
+De même, centraliser la gestion des erreurs détectées pendant
+l'exécutation de la fonction sous un label
+.Ql error ,
+qui vise à revenir à l'état du programme avant l'appel de la fonction,
+et à préparer son retour compte tenu de l'erreur.
+Ses traitements recouvrent notamment la libération de
+l'espace mémorie alloué à destination de l'appelant, la restauration des
+données en mise à jour modifiées par la fonction avant la détection de
+l'erreur, ou la définition de valeurs à destination des variables en
+sortie en conséquence de l'erreur détectée.
+.Pp
+Placer le label
+.Ql error
+après le label
+.Ql exit .
+Terminer la gestion des erreurs par la directive
+.Ql goto exit ,
+de sorte à effectuer les traitements en sortie,
+.Em indépendants
+de la présence ou non d'une erreur d'exécution, et donc à appliquer en
+toute circonstance.
+En structurant les labels de la sorte, les traitements en sortie
+.Pq label Ql exit
+sont ainsi exécutés soit automatiquement au fil du bon déroulé de la
+fonction, sans que l'auteur(e) n'est nécessairement à le préciser.
+Soit après la détection d'une erreur dont la gestion explicite via la
+directive
+.Ql goto error
+précède la sortie de la fonction et ses traitements associés ; auxquels
+renvoit finalement la gestion des erreurs centralisée sous le label
+.Ql error .
+.Bd -literal -offset Ds
+static res_T
+foo(const int bar, int** out_list)
+{
+ int* list = NULL;
+ res_T res = RES_OK;
+
+ if (out == NULL) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if ((list = mem_calloc(42, sizeof(*list)) == NULL) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ if ((res = quux(bar, list)) != RES_OK) goto error;
+
+exit:
+ if (out_list != NULL) *out_list = list;
+ return res;
+error:
+ if (list) { mem_rm(list); list = NULL; }
+ goto exit;
+}
+.Ed
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh LES PROGRAMMES EN LIGNE DE COMMANDE
+Privilégier une interface en ligne de commande pour les programmes
+directement exécutables par l'utilisateur.
+À la fois simple et légère, elle s'intègre parfaitement aux shells, que
+ce soit en session interactive ou via des scripts.
+Avant d'être une interface utilisateur, elle est l'interface avec le
+système UNIX avec lequel le programme peut alors dialoguer, par exemple
+en terme de gestion des entrées/sorties ou de communication
+inter-processus.
+.Pp
+Analyser les arguments du programme en utilisant la fonction
+.Xr getopt 3
+définie par le standard POSIX.1-2001 dans l'en-tête
+.In unistd.h
+de la bibliohtèque C.
+Cette fonction assure la consistante de l'analyse des arguments et
+participe au respect des conventions énoncées par le standard POSIX pour
+les utilitaires en ligne de commandes.
+.Pp
+Proposer l'option
+.Fl h
+qui affiche le seul synopsis de la commande en guise de résumé de ses
+attendus et options.
+Réserver la description du programme et de ses options à sa page de
+manuel.
+Afficher ce même synopsis en cas d'erreur lors de l'analyse des
+arguments de sorte à renvoyer l'utilisateur vers la syntaxe de la
+commande.
+.Bd -literal -offset Ds
+static void
+usage(FILE* stream)
+{
+ fprintf(stream, "usage: foo [-hv] [-b bar]\en");
+}
+
+int
+main(int argc, char** argv)
+{
+ FILE* bar = NULL;
+ int err = 0;
+ int opt = 0;
+ int verbosity = 0;
+
+ while ((opt = getopt(argc, argv, "b:hv")) != -1) {
+ switch (opt) {
+ case 'a':
+ if((bar = fopen(optarg, "r")) == NULL) err = 1;
+ break;
+ case 'h': usage(stdout); goto exit;
+ case 'v': verbosity += (verbosity < 3); break;
+ default: err = 1; break;
+ }
+ if (err) { usage(stderr); goto error; }
+ }
+ if (bar == NULL) bar = stdin;
+
+ if ((err = foo(bar, verbosity)) != 0) goto error;
+
+exit:
+ if(bar && bar != stdin) fclose(bar);
+ return err;
+error:
+ goto exit;
+}
+.Ed
+.Pp
+Dès que possible, donner la possibilité de lire les données d'entrée du
+programme directement sur l'entrée standard.
+Il pourra ainsi être chaîné avec un autre processus en charge, par
+exemple, de pré-traiter ses données d'entrée.
+De même, écrire les données en sortie du programme sur la sortie
+standard pour qu'un autre utilitaire puisse en post-traiter le
+résultat.
+Si plusieurs fichiers d'entrée/de sortie sont lus/écrits par le
+programme, définir les données les plus à même d'être pré/post-traitées
+pour choisir lesquelles seront lues/écriture sur l'entrée/la sortie
+standard.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh FICHIERS
+.Bl -tag -width Ds
+.It Pa @APPPREFIX@/star-style/vimrc
+Fichier de configuration pour l'éditeur
+.Xr vim 1
+qui automatise la mise en page du code C suivant les conventions
+d'écriture définies dans ce manuel.
+Pour l'utiliser, lancer l'éditeur comme suit :
+.Bd -literal -offset Ds
+vim -u @APPPREFIX@/star-style/vimrc
+.Ed
+.El
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh VOIR AUSSI
+.Xr gcc 1 ,
+.Xr vim 1 ,
+.Xr getopt 3 ,
+.Xr feature_test_macros 7
+.Pp
+.Rs
+.%A IEEE
+.%A The Open Group
+.%R Base Definitions, POSIX.1-2001
+.%T Section 12, Utility Conventions
+.Re
+.Pp
+.Rs
+.%A La Fondation pour le logiciel libre
+.%T Comment utiliser les licences GNU pour vos logiciels
+.%U https://www.gnu.org/licenses/gpl-howto.fr.html
+.Re
diff --git a/vimrc b/vimrc
@@ -0,0 +1,91 @@
+" Copyright (C) 2026 |Méso|Star> (contact@meso-star.com)
+" Copyright (C) 2023-2025 Vincent Forest (vaplv@posteo.net)
+"
+" Copying and distribution of this file, with or without modification,
+" are permitted in any medium without royalty provided the copyright
+" notice and this notice are preserved. This file is offered as-is,
+" without any warranty.
+
+syntax on " Enable syntax highlighting
+
+set nocompatible " Do not use Vim just like Vi but allow Vim features
+
+set autoindent " Copy indent from current line when starting a new line
+set backup " Keep a copy of the origin file while writing to an existing file
+set mouse= " Disable the use of the mouse in all modes
+set nohls " Do not highlight all the matches of a search pattern
+set number " Print the line number in front of each line
+set nofoldenable " Disable folding
+set textwidth=72 " Maximum width of text that is being inserted
+
+" Characters to display in list mode (set [no]list),
+" i.e. display hidden characters
+set listchars=eol:$,nbsp:_
+
+" How Backspace, Del, CTRL-W and CTRL-U work in Insert mode
+set backspace=indent,eol,start
+
+" Set 'formatoptions' to break comment lines (c) but not other lines
+" (t). Insert the comment leader (r) when hitting <CR> or using "o" (o).
+" Allow formatting of comments with "gq" (q). Do not automatically
+" format long lones (l), i.e., the ones that exceed 'textwidth'.
+set fo-=t fo+=croql
+
+filetype plugin on " Load the plugin files for specific file types
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" Formatting and indentation of C sources
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" Setup C indentation rules:
+" +2: indent a continuation line inside a function 2 additional characters
+" t0: Indent of a function return type declaration 0 characters
+" from the margin
+" (0: in unclosed parentheses, indent 0 characters from the line with the
+" unclosed parenthesis
+" u0: same as (0 but for one nesting level deeper.
+set cino=+2,t0,(0,u0
+
+" Define as C the filetype of *.h and *.c files.
+" Otherwise, *.h files were defined as C++ files.
+au BufNewFile,BufRead *.h,*.c set filetype=c
+
+au FileType c setlocal tabstop=8 " Number of spaces that a <Tab> in the file counts for
+au FileType c setlocal softtabstop=2 " Number of spaces that a <Tab> counts for while editing
+au FileType c setlocal shiftwidth=2 " Number of spaces to use for each step of (auto)indent
+au FileType c setlocal expandtab " In insert mode, replace <Tab>s by spaces
+
+au FileType c setlocal cindent " Set the cindent option for C files
+au FileType c setlocal textwidth=80 " Set text width for C files
+
+" Setup C comments format rules:
+" "sO:*\ -"
+" Start (s) a comment that is not treated as a normal comment by
+" the o (O) command that insert a new line.
+" It actually starts the comment of a list item (see below).
+" "mO:*\ \ "
+" Add two spaces (\ \ ) after the C comment character (*) when
+" adding a new line (O) in the middle (m) of a list item comment
+" (see above).
+" "exO:*/"
+" End (e) a three piece C comment by typing the last end-comment
+" character (/), as the first action on a new line commenting a
+" list item (x) (see above), i.e. automatically ignore the 2
+" spaces following the '*' character.
+" "s1:/*"
+" Start (s) a three piece C comment (/*).
+" Automatically adds a space offset (1) to the middle or end of
+" the comment leader.
+" "mb:*"
+" Middle (m) of three piece C comment (*).
+" Add a blank (b) after the comment string (*).
+" This avoid to recognize a pointer indirection as a comment.
+" "ex:*/"
+" End (e) of three piece C comment (*/).
+" Allow to close the comment by typing the last char of
+" end-comment (i.e. '/') as the first action on a new
+" middle-comment line (x), i.e. automatically discard the blank
+" following the '*' char.
+" ":///"
+" "://"
+" Continue comments in C99 format on the following lines.
+au Filetype c setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,://