Les macros

Prototype


Des déclarations contenant le spécificateur-déclaration typedef déclare des identificateurs pouvant être utilisés ensuite pour le nommage de types fondamentaux ou dérivés. Le spécificateur typedef ne peut pas être utilisé dans une définition-fonction. La définition des prototypes, dans le manuel, conjointement avec les fichiers d’entête utilise abondamment le typedef. Par exemple :
$ man malloc
...
SYNOPSIS
#include

void *
malloc(size_t size)
...

$ more /usr/include/stdlib.h
...
#include <machine/ansi.h>
...
typedef _BSD_SIZE_T_ size_t;
...

$ more /usr/include/machine/ansi.h
...
#define _BSD_SIZE_T_ unsigned int
...

ce qui permet de traduire :
size_t est l’équivalent de unsigned int.

Utilisation pour les types de données abstraits

L’usage élémentaire consiste à définir un type {\tt Boolean}\footnote {Mammeri M. {\it programmation} {\sc ecole centrale de paris} {\tiny 1997-1998} p. 19 et 36}.
typedef enum { FALSE, TRUE } Boolean ; br L’usage plus élégant consiste à renommer les structures\footnote{{\it ibid.} p.65} :
struct MAILLON
{
TypDon elem ;
struct MAILLON * suiv ;
} ;

typedef struct MAILLON * File ;

On préférera l’écriture en deux étapes à celle plus propice à créer la confusion :
typedef struct MAILLON /* A EVITER */
{
TypDon elem ;
struct MAILLON * suiv ;
} * File ;

Le fichier Liste.tda est un gigantesque typedef qui utilise les possibilités des macros afin de créer des listes d’objets dont le type est défini au moment de l’utilisation.
#define nom(a,b) a##b

#define liste(type_objet)                           \
typedef struct nom(type_objet, liste)               \
{                                                   \
void * rep ;                                        \
type_objet (*copier_objet) (type_objet) ;           \
void (*detruire_objet) (type_objet) ;               \
void (*afficher_objet) (type_objet) ;               \
} * nom(type_objet, liste) ;                        \
nom(type_objet, liste) nom(type_objet, liste_creer) \
(type_objet (*copier) (type_objet),                 \
void (*detruire) (type_objet),                      \
void (*editer) (type_objet))                        \
{                                                   \
nom(type_objet, liste) l ;                          \
lier_liste () ;                                     \
l = (nom(type_objet, liste)) malloc                 \
(sizeof (struct nom (type_objet, liste))) ;         \
l->rep = (*Liste.creer) () ;                     \
l->copier_objet = copier ;                       \
l->detruire_objet = detruire ;                   \
l->afficher_objet = editer ;                     \
return l ;                                          \
}                                                   \
...
void nom(type_objet, liste_afficher)                \
(nom(type_objet, liste) l)                          \
{                                                   \
if (l->afficher_objet)                           \
(*Liste.afficher) (l->rep, l->afficher_objet) ; \
else                                                                                                                                 
                                                    \
printf ("ERR : fonction d'affichage nulle\n") ;     \
}

Remarquez qu’il s’agit d’une seule longue ligne logique, les \ réalisant la concaténation des lignes physiques.
Les macros