🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: fr.comp.lang.c
Article #15319

[FAQ] fr.comp.lang.c - partie 4/4

#15319
From: Guillaume Rumeau
Date: Sun, 02 Oct 2005 09:50
1686 lines
53842 bytes
Archive-Name: fr/comp/lang/faq-c-4

Archive-Name: fr/comp/lang/faq-c-4

---------------------------------------------------------------------------
     FAQ de fr.comp.lang.c

     18 avril 2003
     Partie 4/4 (sections 13 � 17)
---------------------------------------------------------------------------
 

13. Le pr�-processeurs


13.1 Quel est le r�le du pr�processeur ?


    Le pr�processeur interpr�te les directives qui commencent par
    #. Principalement, ces directives permettent d'inclure
    d'autres fichiers (via #include) et de d�finir des
    macros (via #define) qui sont remplac�es lors de la
    compilation.

    
    Chaque directive de compilation commence par un # situ�
    en d�but de ligne (mais �ventuellement pr�c�d� par des espaces,
    des tabulations ou des commentaires) et se termine en fin de
    ligne.

    
    Le pr�processeur est �galement responsable de la reconnaissance
    des trigraphes, des backslashs terminaux, et de
    l'ablation des commentaires.


13.2 Qu'est-ce qu'un trigraphe ?


    Dans les temps anciens, les ordinateurs n'utilisaient pas ASCII ;
    chaque machine avait son propre jeu de caract�res. L'ISO a d�fini
    un jeu de caract�res suppos�s pr�sents sur toutes les machines,
    c'est l'Invariant Code Set ISO 646-1983. Ce jeu de
    caract�res ne comporte pas certains caract�res int�ressants, tels
    que les accolades et le backslash. Aussi, le standard
    C89 a introduit les trigraphes, s�quences de trois caract�res
    commen�ant par ??.
    Il existe neuf s�quences remplac�es par le pr�processeur.
    Ce remplacement a lieu avant toute autre op�ration, et agit
    �galement dans les commentaires, les cha�nes constantes, etc.

    
    Les trigraphes sont, de fait, rarement utilis�s. On les voit
    appara�tre occasionnellement et par erreur, quand on �crit �a :

    
    printf("Kikoo ??!\n");
    

    Le trigraphe est remplac� par un pipe, donc ce code
    affiche ceci :

    
    Kikoo |
    

    De toutes fa�ons, le redoublement du point d'interrogation est de
    mauvais go�t.

    
    Les compilateurs modernes soient ne reconnaissent plus les
    trigraphes, soit �mettent des avertissements quand ils les
    rencontrent.


13.3 � quoi sert un backslash en fin de ligne ?


    Apr�s le remplacement des trigraphes, le pr�processeur recherche
    tous les caract�res backslash situ�s en fin de ligne
    ; chaque occurrence de ce caract�re est supprim�e, de m�me que le
    retour � la ligne qui le suit. Ceci permet d'unifier plusieurs
    lignes en une seule.

    
    Ce comportement est pratique pour �crire des macros ou des
    cha�nes de caract�res sur plusieurs lignes :

    
    printf("Hello\
     World !\n");
    

    Pour les cha�nes de caract�res, on peut aussi �crire plusieurs
    cha�nes c�te � c�te, et le compilateur les unifiera (mais pas le
    pr�processeur : pour lui, ce seront deux cha�nes � la suite l'une
    de l'autre). C'est une technique qui doit �tre g�n�ralement pr�f�r�e.
    On �crira donc pour l'exemple pr�c�dent :

    
    printf("Hello"
           "World !\n");
    

13.4 Quelles sont les formes possibles de commentaires ?


    Un commentaire en C commence par /* et se termine par
    */, �ventuellement plusieurs lignes plus loin. Les
    commentaires ne s'imbriquent pas.

    
    On peut aussi utiliser la compilation conditionnelle, comme ceci :

    
    #if 0
        /* ceci est ignore */
    #endif /* 0 */
    

    Dans ce cas, il faut que ce qui est ignor� soit une suite de
    tokens valide (le pr�processeur va quand m�me les
    regarder, afin de trouver le #endif). Ceci veut dire
    qu'il ne faut pas de cha�ne non termin�es. Ce genre de
    commentaire n'est pas adapt� � du texte, � cause des apostrophes.

    
    La nouvelle norme du C (C99) permet d'utiliser les commentaires
    du C++ : ils commencent par // et se terminent en fin de
    ligne. Ce type de commentaire n'est pas encore support� partout,
    donc mieux vaut ne pas s'en servir si on veut faire du code vraiment
    portable, m�me si avant C99, des compilateurs acceptaient ce type 
    de commentaires. 


13.5 Comment utiliser #include ?


    #include comporte trois formes principales :

    
    #include <fichier>
    #include "fichier"
    #include tokens
    

    La premi�re forme recherche le fichier indiqu� dans les
    r�pertoires syst�me ; on peut les ajuster soit via des menus (dans
    le cas des compilateurs avec une interface graphique), soit en
    ligne de commande. Sur un syst�me Unix, le r�pertoire
    syst�me classique est /usr/include/. Une fois le fichier
    trouv�, tout se passe comme si son contenu �tait tel quel dans le
    code source, l� o� se trouve le #include.

    
    La deuxi�me forme recherche le fichier dans le r�pertoire
    courant. Si le fichier ne s'y trouve pas, il est ensuite cherch�
    dans les r�pertoires syst�mes, comme dans la premi�re forme.

    
    La troisi�me forme, o� ce qui suit le #include ne
    correspond pas � une des deux formes pr�c�dentes, commence par
    effectuer tous les remplacements de macros dans la suite de
    tokens, et le r�sultat doit �tre d'une des deux formes
    pr�c�dentes.

    
    Si le fichier n'est pas trouv�, c'est une erreur, et la
    compilation s'arr�te. On notera que si on se sert d'habitude de
    #include pour inclure des fichiers d'en-t�te (tels que
    stdio.h), ce n'est pas une obligation.


13.6 Comment �viter l'inclusion multiple d'un fichier ?


    Il arrive assez souvent qu'un fichier inclus en incluse un autre,
    qui lui-m�me en inclut un autre, etc. On peut arriver � des
    boucles, qui peuvent conduire � des redoublements de d�clarations
    (donc des erreurs, pour typedef par exemple), voire des
    boucles infinies (le compilateur finissant par planter).

    
    Pour cela, le moyen le plus simple est de � prot�ger � chaque
    fichier par une construction de ce genre :

    
    #ifndef FOO_H_
    #define FOO_H_
    /* ici, contenu du fichier */
    #endif /* FOO_H_ */
    

    Ainsi, m�me si le fichier est inclus plusieurs fois, son contenu
    ne sera actif qu'une fois. Certains pr�processeurs iront m�me
    jusqu'� reconna�tre ces structures, et ne pas lire le fichier
    si la macro de protection (ici FOO_H_) est encore
    d�finie.

    
    Il y a eut divers autres moyens propos�s, tels que #import
    ou #pragma once, mais ils ne sont pas standards, et encore
    moins r�pandus.


13.7 Comment d�finir une macro ?


    On utilise #define. La forme la plus simple est la
    suivante :

    
    #define FOO  3 + 5
    

    Apr�s cette d�claration, toute occurrence de l'identificateur
    FOO est remplac�e par son contenu (ici 3 + 5).
    Ce remplacement est syntaxique et n'a pas lieu dans les cha�nes
    de caract�res, ou dans les commentaires (qui n'existent d�j� plus,
    de toutes fa�ons, � cette �tape).

    
    On peut d�finir un contenu vide. La macro sera remplac�e, en cas
    d'utilisation, par rien. Le contenu de la macro est une suite
    de tokens du C, qui n'a pas � vouloir dire quelque
    chose. On peut d�finir ceci, c'est valide :

    
    #define FOO  (({/coucou+}[\}+ "zap" 123
    

    La tradition est d'utiliser les identificateurs en majuscules pour
    les macros ; rien n'oblige cependant � appliquer cet usage. Les
    r�gles pour les identificateurs de macros sont les m�mes que pour
    celles du langage.


13.8 Comment d�finir une macro avec des arguments ?


    On fait ainsi :

    
    #define FOO(x, y)   ((x) + (x) * (y))
    

    Ceci d�finit une macro qui attend deux arguments ; notez qu'il
    n'y a pas d'espace entre le nom de la macro (FOO) et la
    parenth�se ouvrante. Toute invocation de la macro par la suite
    est remplac�e par son contenu, les arguments l'�tant aussi.
    Ainsi, ceci :

    
    FOO(bla, "coucou")
    

    devient ceci :

    
    ((bla) + (bla) * ("coucou"))
    

    (ce qui ne veut pas dire grand'chose en C, mais le pr�processeur
    n'en a cure). Le premier argument est remplac� deux fois, donc,
    s'il a des effets de bord (appel d'une fonction, par exemple),
    ces effets seront pr�sents deux fois.

    
    Si la macro est invoqu�e sans arguments, elle n'est pas
    remplac�e. Cela permet de d�finir une macro sens�e remplacer une
    fonction, mais en conservant la possibilit� d'obtenir un pointeur
    sur la fonction.
    Ainsi :

    
    int min(int x, int y) { return x < y ? x : y; }
    #define min(x, y)   ((x) < (y) ? (x) : (y))
    min(3, 4);    /* invocation de la macro */
    (min)(3, 4);  /* invocation de la fonction, via le pointeur */
    

    C'est une erreur d'invoquer une macro � argument avec un nombre
    incorrect d'arguments. En C99, on peut utiliser des arguments
    vides ; en C89, c'est flou et mieux vaut �viter.


13.9 Comment faire une macro avec un nombre variable d'arguments ?


    Ce n'est possible qu'en C99. On utilise la construction suivante :

    
    #define error(l, ...)    { \
            fprintf(stderr, "line %d: ", l); \
            fprintf(stderr, __VA_ARGS__); \
        }
    

    Ceci d�finit une macro, qui attend au moins un argument ; tous
    les arguments suppl�mentaires sont concat�n�s, avec leurs virgules
    de s�paration, et on peut les obtenir en utilisant
    __VA_ARGS__. Ainsi, ceci :

    
    error(5, "boo: '%s'\n", bla)
    

    sera remplac� par ceci :

    
    { fprintf(stderr, "line %d: ", 5); \
      fprintf(stderr, "boo: '%s'\n", bla); }
    

    Ce m�canisme est support� par les derni�res versions de la plupart
    des compilateurs C actuellement d�velopp�s ; mieux vaut l'�viter
    si le code doit aussi fonctionner avec des compilateurs un peu
    plus anciens.

    
    Il existe aussi des extensions sur certains compilateurs. Par exemple,
    sous GCC, le code suivant est �quivalent � l'exemple pr�c�dent :

    
    #define error(l, format...)    { \
            fprintf(stderr, "line %d: ", l); \
            fprintf(stderr, format); \
        }
    

    Une autre m�thode consiste � utiliser le parenth�sage des arguments :
    
    #define PRINTF(s) printf s
    ...
    PRINTF (("Vitesse du vent %d m/s", v));
    

13.10 Que font les op�rateurs # et ## ?

    L'op�rateur # permet de transformer un argument d'une
    macro en une cha�ne de caract�res. On fait ainsi :

    
    #define BLA(x)    printf("l'expression '%s' retourne %d\n", #x, x);
    BLA(5 * x + y);
    

    ce qui donne le r�sultat suivant :

    
    printf("l'expression '%s' retourne %d\n", "5 * x + y", 5 * x + y);
    

    Les �ventuelles cha�nes de caract�res et backslashs dans
    l'argument sont prot�g�s par des backslashes, afin de
    constituer une cha�ne valide.

    
    L'op�rateur ## effectue la concat�nation de deux
    tokens. Si le r�sultat n'est pas un
    token valide, alors c'est une erreur ; mais certains
    pr�processeurs sont peu stricts et se contentent de re-s�parer
    les tokens.
    On l'utilise ainsi :

    
    #define FOO(x, y)   x ## y
    FOO(bar, qux)();
    

    qui donne ceci :

    
    barqux();
    

13.11 Une macro peut-elle invoquer d'autres macros ?


    Oui. Mais il est pr�vu un m�canisme qui emp�che les boucles
    infinies.

    
    Tout d'abord, les invocations de macros ne sont constat�es que
    lors de l'utilisation de la macro, pas lors de sa d�finition.
    Si on fait ceci :

    
    #define FOO    BAR
    #define BAR    100
    

    alors on obtient bien 100, pas BAR.

    
    Si la macro poss�de des arguments, chaque fois que cet argument
    est utilis� (sans �tre pr�c�d� d'un # ou pr�c�d� ou suivi
    d'un ##), il est d'abord examin� par le pr�processeur,
    qui, s'il y reconna�t une macro, la remplace. Une fois les
    arguments trait�s, le pr�processeur les implante � leur place
    dans la suite de tokens g�n�r�s par la macro, et g�re
    les op�rateurs # et ##.

    
    � la suite de cette op�ration, le r�sultat est de nouveau examin�
    pour rechercher d'autres remplacements de macros ; mais si une
    macro est trouv�e, alors qu'on est dans le remplacement de ladite,
    cette macro n'est pas remplac�e. Ceci �vite les boucles infinies.

    
    Je sais, c'est compliqu�. Quelques exemples :

    
    #define FOO    coucou BAR
    #define BAR    zoinx FOO
    FOO
    

    FOO est remplac�e par coucou BAR, et le
    BAR r�sultant est remplac� par zoinx FOO. Ce
    FOO n'est pas remplac�, parce qu'on est dans le
    remplacement de FOO. Donc, on obtient coucou zoinx
    FOO.

    
    Un autre exemple, plus tordu :

    
    #define FOO(x)   x(5)
    FOO(FOO);
    

    La macro FOO est invoqu�e ; elle attend un argument, qui
    est FOO. Cet argument est d'abord examin� ; il y a
    FOO dedans, mais non suivi d'une parenth�se ouvrante
    (l'argument est examin� tout seul, ind�pendamment de ce qui le
    suit lors de son usage), donc le remplacement n'a pas
    lieu. Ensuite, l'argument est mis en place, et on obtient
    FOO(5). Ce r�sultat est r�examin� ; cette fois,
    FOO est bien invoqu�e avec un argument, mais on est dans
    le deuxi�me remplacement, � l'int�rieur de la macro FOO,
    donc on ne remplace pas.
    Le r�sultat est donc : FOO(5);

    
    Si vous voulez utiliser ce m�canisme, allez lire une douzaine
    de fois la documentation du GNU cpp, et surtout le
    paragraphe 12 de l'annexe A du Kernighan &
    Ritchie (2�me �dition).


13.12 Comment red�finir une macro ?


    On peut red�finir � l'identique une macro ; ceci est pr�vu pour
    les fichiers d'en-t�te inclus plusieurs fois. Mais il est en
    g�n�ral plus sain de prot�ger ses fichiers contre l'inclusion
    multiple (cf. 13.6).

    
    Red�finir une macro avec un contenu ou des arguments diff�rents,
    est une erreur. Certains pr�processeurs laxistes se contentent
    d'un avertissement. La bonne fa�on est d'abord d'ind�finir la
    macro via un #undef. Ind�finir une macro qui n'existe
    d�j� pas, n'est pas une erreur.


13.13 Que peut-on faire avec #if ?

    #if permet la compilation conditionnelle. L'expression
    qui suit le #if est �valu�e � la compilation, et, suivant
    son r�sultat, le code qui suit le #if jusqu'au prochain
    #endif, #elif ou #else est
    �valu�, ou pas.
    Quand le code n'est pas �valu�, les directives de pr�processeur
    ne le sont pas non plus ; mais les #if et similaires sont
    n�anmoins compt�s, afin de trouver la fin de la zone non compil�e.

    
    Lorsque le pr�processeur rencontre un #if, il :
    
         -  r�cup�re l'expression qui suit le #if
         -  remplace les defined MACRO et
            defined(MACRO) par la constante 1 si
            la macro nomm�e est d�finie, 0 sinon
         -  remplace les macros qui restent dans l'expression
         -  remplace par la constante 0 tous les
            identificateurs qui restent
         -  �value l'expression
    

    L'expression ne doit comporter que des constantes enti�res (donc,
    �ventuellement, des constantes caract�res), qui sont promues au
    type (unsigned) long (en C89) ou (u)intmax_t (en
    C99). Les flottants, les pointeurs, l'acc�s � un tableau, et
    surtout l'op�rateur sizeof ne sont pas utilisables par le
    pr�processeur.

    
    Il n'est pas possible de faire agir un #if suivant
    sizeof(long), pour reprendre un desiderata
    fr�quent. Par ailleurs, les constantes de type caract�re n'ont pas
    forc�ment la m�me valeur pour le pr�processeur et pour le
    compilateur.


13.14 Qu'est-ce qu'un #pragma ?


    C'est une indication pour le compilateur. Le pr�processeur
    envoie cette directive sans la modifier. Le standard C89 ne
    pr�voit aucune directive standard, mais le pr�processeur
    comme le compilateur sont sens�s ignorer les directives
    inconnues.

    
    Le C99 d�finit trois #pragma qui permettent d'ajuster
    le comportement du compilateur, quant au traitement des nombres
    flottants et complexes.


13.15 Qu'est-ce qu'un #assert ?


    C'est une extension g�r�e par GNU et (au moins) le
    compilateur Sun (Workshop Compiler, pour
    Solaris). C'est une sorte d'alternative �
    #ifdef, avec une syntaxe plus agr�able.
    C'est � �viter, car non standard.


13.16 Comment d�finir proprement une macro qui comporte plusieurs statements ?

    On peut ouvrir un bloc, car tout statement est
    rempla�able, en C, par un bloc, mais cela pose des probl�mes avec
    le ; terminal du statement. La mani�re
    recommand�e est la suivante :

    
    #define foo(x)   do { f(x); printf("coucou\n"); } while (0)
    

    On peut ainsi l'utiliser comme ceci :

    
    if (bar) foo(1); else foo(2);
    

    Si on avait d�fini foo sans le do et le
    while (0), le code ci-dessus aurait provoqu� une erreur
    de compilation, car le else serait s�par� du if
    par deux statements : le bloc et le statement vide, termin� par le
    point-virgule.


13.17 Comment �viter les effets de bord ?

    Les macros peuvent �tre dangereuses si l'on ne fait
    pas attention aux effets de bord. Par exemple si l'on
    a le code suivant :

    
    #define MAX   3 + 5

    int i = MAX;
    

    La variable i vaudra bien 8, mais si on utilise la
    macro MAX ainsi :

    
    int i = MAX * 2;
    

    La variable i ne vaudra pas 16, mais 13. Pour �viter
    ce genre de comportement, il faut �crire la macro
    ainsi :

    
    #define MAX   (3 + 5)
    

    Dans certains cas, une macro repr�sente une expression C
    compl�te. Il est alors plus coh�rent de placer des parenth�ses
    vides pour simuler une fonction. Et dans ce cas il ne faut pas la
    terminer par un point virgule, et

    
    #define PRTDEBUG()   (void)printf("Coucou\n")
    

    ainsi, on pourra utiliser la macro par :

    
    if (i == 10) {
       PRTDEBUG();
    }
    else {
       i++;
    }
    

    Quand une macro a des arguments il faut faire attention
    � la fa�on de les utiliser. Ainsi la macro :

    
    #define CALCUL(x, y)   (x + y * 2)
    

    a des effets de bord suivant la fa�on de l'utiliser :

    
    int i = CALCUL(3, 5);
    

    donnera bien un r�sultat de 13, alors que le m�me r�sultat
    serait attendu avec :

    
    int i = CALCUL(3, 2 + 3);
    

    qui donne 11. Pour �viter cela, il suffit de placer des
    parenth�ses sur les arguments de la macro:

    
    #define CALCUL(x, y)   ((x) + (y) * 2)
    

    Un effet de bord qui ne peut �tre contourn� survient quand
    la macro utilise plusieurs fois une variable :

    
    #define MAX(x, y)   ((x) > (y) ? (x) : (y))
    

    Si on utilise la macro comme cela :

    
    i = MAX(j, k);
    

    On obtiendra un r�sultat correct, alors qu'avec :

    
    i = MAX(j++, k++);
    

    une des variables j ou k sera incr�ment�e 2
    fois. Pour �viter ce genre de comportement, il faut remplacer la
    macro par une fonction, de pr�f�rence inline (C99) :

    
    inline int max(int x, int y)
    {
        return x > y ? x : y;
    }
    

    En r�gle g�n�rale, quand on utilise une fonction avec un nom
    en majuscule (comme MAX), on s'attend � ce que ce soit en fait
    une macro, avec les effets de bord qui en d�coulent. Alors que
    si le nom est en minuscule, il s'agit s�rement d'une v�ritable
    fonction. Cette r�gle n'est h�las pas g�n�rale et donc il
    convient de v�rifier le v�ritable type d'une fonction si l'on
    ne veut pas �tre surpris lors de son utilisation.


13.18 Le pr�processeur est-il vraiment utile ?

    La r�ponse est oui. Il existe un mouvement qui voudrait faire
    dispara�tre le pr�processeur, en rempla�ant les #define
    par des variables constantes, et avec un quelconque artifice
    syntaxique pour importer les d�clarations d'un fichier d'ent�te.

    
    Il s'av�re qu'on a vraiment besoin d'un m�canisme polymorphe
    (comme une fonction qui accepterait plusieurs types diff�rents),
    et que seules les macros apportent ce m�canisme en C. Les
    anti-pr�processeurs acharn�s parlent d'adopter le m�canisme
    des templates du C++, mais �a ne risque pas d'arriver de sit�t.

    
    Dans la vie de tous les jours, l'utilisation du pr�processeur,
    avec quelques #include et des #define sans
    surprise, ne pose pas de probl�me particulier, ni de maintenance,
    ni de portabilit�.


13.19 Approfondir le sujet.


    Outre le Kernighan & Ritchie, qui comporte
    quelques pages tr�s bien faites sur le sujet, on peut lire la
    documentation au format info du GNU cpp ;
    elle est assez partiale dans certains cas (condamnation explicite
    des trigraphes, par exemple) mais assez riche en enseignements.

    
    Pour le reste, chaque compilateur C vient avec un pr�processeur,
    et il existe quelques pr�processeurs ind�pendants (un �crit
    par Dennis Ritchie en personne, qu'on voit inclus dans
    lcc, et aussi ucpp, une oeuvre � moi :
    <http://www.di.ens.fr/~pornin/ucpp/>).


14. Fonctions de la biblioth�que


14.1 Comment convertir un nombre en une cha�ne de caract�res ?


    Il suffit d'utiliser sprintf().

    
    char sz[4];
    sprintf(sz, "%d", 123);
    

    Pour convertir un double ou un long,
    il faut utiliser %f ou %ld.

    
    Le probl�me de sprintf() est qu'il faut r�server
    assez de place pour la cha�ne r�sultat. Ainsi le code

    
    char sz[6];
    sprintf(sz, "%u", i);
    

    marchera sur des machines o� i est un entier 16 bits,
    mais il plantera si i est un entier plus grand (>
    99999).

    
    En C99, la fonction snprintf permet d'�viter les d�bordements :

    
    char sz[4];
    n = snprintf(sz, sizeof sz, "%d", 123);
    if (n < 0 || n >= sizeof sz)
        erreur();
    

14.2 Comment convertir une cha�ne en un nombre ?


    Si le nombre esp�r� est un entier, il faut utiliser la fonction
    strtol(). Elle convertit une cha�ne en un entier long,
    dans une base donn�e.

    
    Si le nombre est un r�el (float ou double),
    alors la fonction strtod() fera tr�s bien l'affaire.

    
    char test[] = "  -123.45e+2";
    char * err = NULL;

    errno = 0;
    double result = strtod(test, &err);

    if (err == test) {
        printf("Erreur de conversion :\n");
    } 
    else if (errno == ERANGE) {
        printf("Depassement :\n");
    } 
    else {
        printf("Conversion reussie :\n");
        if(*err == '\0') {
            printf("Pour toute la chaine\n");
        }
    }
    

    Si le nombre est un long double (C99 seulement) alors la
    fonction strtold() est � pr�f�rer.


14.3 Comment d�couper une cha�ne ?


    La fonction strtok() est faite pour �a !

    
    char sz1[] = "this is,an   example ; ";
    char sz2[] = ",; ";
    char *p;

    p = strtok(sz1, sz2);
    if (p != NULL) {
        puts(p);
        while ((p = strtok(NULL, sz2)) != NULL) {
            puts(p);
        }
    }
    

    Attention, la fonction strtok() souffre au moins des
    probl�mes / caract�ristiques suivants :
    
         - Elle fusionne les d�limiteurs adjacents. En cas
        d'utilisation d'une virgule comme s�parateur, "a,,b,c" est
        s�par�e en trois �l�ments et non quatre.
         - Le caract�re du d�limiteur est perdu, car il est
        remplac� par un caract�re nul (0).
         - Elle modifie la chaine qu'elle analyse. C'est un
        d�faut, car cela oblige � faire une copie de la chaine en cas
        d'utilisation ult�rieure. Cela signifie aussi que l'on ne peut
        pas s�parer une chaine litt�rale avec.
         - On ne peut utiliser qu'un appel de cette fonction � la
        fois. Si une s�quence de strok() est en cours, et
        qu'une autre d�marre, l'�tat de la premi�re est perdue. Ce
        n'est pas grave pour les petits programmes, mais il est facile
        de se perdre dans la hi�rarchie des fonctions imbriqu�es dans
        des programmes plus importants. En d'autre termes,
        strtok() brise les principes de l'encapsulation. 
   
    
    Dans des cas simples, on pourra utiliser la fonction
    strchr().


14.4 Pourquoi ne jamais faire fflush(stdin) ?


    La fonction fflush() a un comportement d�fini
    uniquement sur les flux ouverts en �criture tels que
    stdout. Il est possible que sur votre syst�me, appliquer
    cette fonction � stdin soit possible, mais c'est alors
    une extension non standard. Le comportement est ind�termin�, et
    impr�visible.

    
    Il faut bien comprendre que stdin n'est pas forc�ment
    reli� au clavier, mais peut �tre rattach� � un r�seau, un fichier,
    etc.


14.5 Comment vider le buffer associ� � stdin ?


    Une bonne mani�re est de lire sur le flux tant qu'il n'est pas
    vide, avec les fonctions habituelles comme fgets() ou
    getchar().
    Voici un exemple avec cette derni�re :

    
    c = getchar();
    if (c != '\n')
        while ( (getchar()) !=  '\n') {
    };
    

    Ce morceau de code permet de lire un caract�re, et vide ce qui
    peut rester dans le buffer, notamment le '\n' final.


14.6 Pourquoi mon printf() ne s'affiche pas ?


    Le flux standard stdout, sur lequel �crit
    printf() est bufferis�. C'est � dire que les caract�res
    sont �crits dans un tampon (une zone m�moire). Lorque celui-ci est
    plein, ou lorsqu'une demande explicite est faite, il est vid� dans
    le flux proprement dit (sur l'�cran g�n�ralement).
    Tant que le buffer n'est pas vid�, rien ne s'affiche.

    
    Pour vider le buffer, il y a trois possibilit�s :

    
     -  Le buffer est plein
     -  Il est vid� explicitement par l'appel de la
    fonction fflush()
    (cf. 14.4)
     -  La cha�ne de caract�res se termine par un
    '\n'
    

14.7 Comment obtenir l'heure courante et la date ?


    Il faut simplement utiliser les fonctions time(),
    ctime() et/ou
    localtime(), qui contrairement � leurs noms donnent
    l'heure et la date.

    
    Voici un petit exemple :

    
    #include <stdio.h>
    #include <time.h>

    int main(void) {
        time_t now;
        time(&now);

        printf("Il est %.24s.\n", ctime(&now));

        return 0;
    }
    

14.8 Comment faire la diff�rence entre deux dates ?


    Il faut simplement utiliser la fonction difftime().
    Cette fonction prend deux time_t en param�tres et renvoie
    un double.


14.9 Comment construire un g�n�rateur de nombres al�atoires ?


    Ce n'est pas possible.
    La biblioth�que standard inclut un g�n�rateur pseudo-al�atoire,
    la fonction rand().

    Toutefois, l'impl�mentation d�pend du syst�me, et celle-ci n'est
    g�n�ralement pas tr�s bonne (en terme de r�sultats statistiques).
    Si rand() ne vous suffit pas (simulation num�rique ou
    cryptologie), il vous faudra regarder du cot� de
    biblioth�ques math�matiques, dont de nombreuses se trouvent sur
    Internet. En particulier, on consultera les paragraphes 7-0 et 7-1
    des Numerical Recipes in C (cf.
    4.5) et le volume 2 de TAoCP
    (cf. 3.9).


14.10 Comment obtenir un nombre pseudo-al�atoire dans un intervalle ?


    La m�thode la plus simple � faire,

    
    rand() % N
    

    qui renvoie un nombre entre 0 et N-1 est aussi
    la moins bonne.
    En effet, les bits de poids faibles ont une distribution tr�s peu
    al�atoire. Par exemple, le bit de poids le plus faible a une
    distribution qui peut �tre celle-ci sur un mauvais g�n�rateur :

    0 1 0 1 0 1 0 1 0 1 ... 

    
    Voici la m�thode pr�conis�e dans Numerical Recipes
    (cf.4.5) :

    
    (int)((double)rand() / ((double)RAND_MAX + 1) * N)
    

    RAND_MAX est d�fini dans stdlib.h,
    et N doit �tre plus petit que RAND_MAX.


14.11 � chaque lancement de mon programme, les nombres pseudo-al�atoires sont toujours les m�mes ?


    C'est normal, et c'est fait expr�s. Pour contrer cela, il faut
    utiliser une graine pour le g�n�rateur qui change � chaque
    lancement du programme. C'est la fonction srand() qui
    s'en charge.

    
    On peut utiliser l'heure syst�me, avec time(), de la
    facon suivante :

    
    srand(time(NULL));
    

    Notez qu'il est peu utile d'appeler la fonction srand()
    plus d'une fois par programme.


14.12 Comment savoir si un fichier existe ?


    En C ISO, le seul moyen de savoir si un fichier existe, c'est
    d'essayer de l'ouvrir.

    
    {
       FILE *fp = fopen ("fichier.txt", "r");
    
       if (fp == NULL)
       {
          fputs ("Le fichier n'existe pas,\n"
                 "ou vous n'avez pas les droits necessaires\n"
                 "ou il est inaccessible en ce moment\n"
                 , stderr);
       }
       else
       {
          /* ... operation sur le fichier */ 
    
          fclose(fp);
       } 
    }
    

    Dans la norme POSIX, il existe la fonction
    access(), mais certains syst�mes n'impl�mentent pas
    cette interface.


14.13 Comment conna�tre la taille d'un fichier ?


    Malheureusement, les fonctions stat() et
    fstat() de la norme POSIX ne sont pas
    reprises dans la norme ISO.
    La seule solution standard est d'utiliser fseek() et
    ftell().

    Toutefois, cela ne marche pas pour les tr�s gros fichiers
    (sup�rieurs � LONG_MAX).


14.14 Comment lire un fichier binaire proprement ?


    Il faut ouvrir le fichier en mode � binaire �, en passant la cha�ne
    "rb"
    en mode d'ouverture � la fonction fopen().
    Cela �vite les transformations inopportunes et les probl�mes des
    caract�res de contr�le.

    
    De m�me, pour �crire dans un fichier binaire, on utilise le mode
    "wb".


14.15 Comment marquer une pause dans un programme ?


    Il n'y a pas de fonction standard pour cela.
    Il existe toutefois la fonction sleep() en
    POSIX, elle provoque une attente passive pour une
    dur�e donn�e en secondes.


14.16 Comment trier un tableau de cha�nes ?


    La fonction qsort() est une bonne fonction de tri,
    qui impl�mente le Quick Sort.
    Le plus simple est de donner un exemple :

    
    /* Fonction qui compare deux pointeurs
       vers des chaines pour qsort */
    int pstrcmp(const void * p1, const void * p2){
        return strcmp(*(char * const *)p1, *(char * const *)p2);
    }
    

    Les param�tres doivent �tre des pointeurs g�n�riques pour
    qsort().
   p1 et p2 sont des pointeurs sur des cha�nes.
    Un tableau de cha�nes doit �tre pris au sens d'un tableau de
    pointeurs vers des char *.

    
    L'appel � qsort() ressemble alors � :

    
    qsort(tab, sizeof tab, sizeof *tab, pstrcmp);
    

14.17 Pourquoi j'ai des erreurs sur les fonctions de la biblioth�que, alors que j'ai bien inclus les ent�tes ?


    Les en-t�tes (les .h) ne contiennent que les
    prototypes des fonctions.
    Le code proprement-dit de ces fonctions se trouve dans des
    fichiers objets. Ce code doit �tre � li� � au tien. Cela est fait
    par un �diteur de liens.

    
    Pour certaines fonctions, il faut sp�cifier explicitement �
    l'�diteur de liens o� il peut les trouver (et ce particuli�rement
    pour les fonctions non-standard).

    
    Par exemple, sous Unix, pour utiliser les fonctions math�matiques,
    il faut g�n�ralement lier le programme avec la biblioth�que ad�quate :

    
    cc -lm monfic.o -o monprog
    

15. Styles


15.1 Comment bien programmer en C ?


    La chose la plus importante est de commenter un programme.
    Il ne s'agit pas de d�crire en fran�ais tout ce que fait chaque
    ligne de code, mais de pr�ciser le fonctionnement des op�rations
    complexes, d'expliquer le r�le des variables, de dire � quoi
    servent les fonctions. Choisir des noms de variables et de
    fonctions explicites est une bonne fa�on de commenter un
    programme.

    
    Tout morceau de code qui n'est pas standard doit �tre abondamment
    comment� afin de rendre le portage vers d'autres cibles le moins
    fastidieux possible, l'id�al �tant d'utiliser des macros.

    
    Il est �galement important de bien structurer son programme en
    modules, puis en fonctions.
    Certains vont jusqu'� dire qu'une fonction ne doit pas d�passer la
    taille d'un �cran.

    
    Les d�clarations et prototypes doivent �tre regroup�s dans des
    fichiers d'en-t�tes, avec les macros.

    
    Enfin, il est tr�s important de bien pr�senter le code, avec une
    indentation judicieuse et des sauts de
    ligne. (cf. 15.2)
    Il est g�n�ralement admis que les lignes ne doivent pas d�passer
    80 caract�res.

    
    Pour le reste, c'est une histoire de go�t.


15.2 Comment indenter proprement du code ?


    L'indentation du code est une chose essentielle pour la
    lisibilit�. Certaines personnes utilisent des tabulations, ce qui
    est une mauvaise habitude. La largeur de ces tabulations varie
    d'un �diteur � un autre. Des �diteurs remplacent les tabulation
    par un nombre d'espaces fixe et d'autres encore utilisent des
    tabulations de taille variable. Ne parlons pas des imprimantes ou
    des lecteurs de news...
    Tout ceci rend l'utilisation des tabulations difficile.

    
    Pour �viter tout probl�me, et am�liorer la lisibilit� du code,
    il faut utiliser uniquement des espaces.
    Un �diteur correct doit pouvoir g�n�rer un nombre d'espaces fixe
    (voire une indentation automatique) lorsqu'on appuye sur la touche
    <TAB> (ou autre raccourci).
    Personnellement, je r�gle � 4 espaces par tabulation.


15.3 Quel est le meilleur style de programmation ?


    Comme vous vous en doutez, il n'y en a pas.
    Le plus important est d'en avoir un, et de le suivre.
    Quand on utilise un type d'indentation ou un style de nommage,
    il faut l'utiliser dans tout le programme (voire dans tout ses
    programmes). C'est la r�gularit� qui donne la lisibilit�.

    
    Il existe des styles de programmations fr�quemment utilis�s en C,
    comme les styles K&R ou GNU.
    Le style K&R est le style � historique �, et
    c'est pourquoi il est tr�s utilis�.
    Le style GNU est utilis� pour tous les projets de la
    Free Software Fundation.

    
    Sur le site FTP <ftp://caramba.cs.tu-berlin.de>,
    le repertoire /pub/doc/style contient quelques
    documents int�ressants sur la question.


15.4 Qu'est-ce que la notation hongroise ?


    C'est une convention de nommage des objets, invent�e par Charles
    Simonyi. Le principe est de faire pr�c�der le nom des
    variables par un identificateur de type.
    Par exemple, une cha�ne de caract�re repr�sentant un nom sera
    nomm�e szname, sz signifiant � string
    zero �, ou cha�ne termin�e par un '\0'.

    
    Personnellement, je ne trouve pas cette convention toujours
    pratique. Le nom de la variable doit avant tout refl�ter son r�le.


15.5 Pourquoi certains �crivent-ils if(0==x) et non if(x==0) ?


    Il arrive souvent que l'on �crive = au lieu de
    ==. Comme 0 n'est pas une lvalue
    (cf. 10.10), cette �tourderie
    provoquera une erreur, simple � d�tecter.
    Dans le m�me genre, on peut �crire while (0 == x).

    
    Certains compilateurs pr�viennent lorsque l'on fait une
    affectation l� ou est attendu un test. C'est le cas de GNU
    CC, avec l'option -Wall.

    
    Lorsque l'on �crit while ( c = fct() ), certains
    compilateurs r�lent en croyant que l'on s'est tromp� entre le
    = et le ==. Pour �viter cela, il suffit de
    rajouter un paire de parenth�ses.

    
    while ( (c= fct()) ) {
        /* ... */
    }
    

15.6 Pourquoi faut-il mettre les '{' et '}' autour des boucles ?


    C'est une pr�caution contre les erreurs du genre :

    
    for(i = 0; i < N; i++);
        tab[i] = i;
    

    De plus, cela permet une plus grande simplicit� dans l'�volution
    du code. En effet, les programmes ont tendance � s'�paissir avec
    le temps.


15.7 Pourquoi certains disent-ils de ne jamais utiliser les goto ?


    Le goto est une instruction qui permet de casser l'aspect
    structur� d'un programme. Des goto mal utilis�s
    permettent de rendre un code totalement illisible (code
    spaghetti), d'autant plus qu'avec les structures de
    boucles traditionnelles, on peut souvent s'en passer.

    
    Toutefois, il arrive parfois que l'utilisation d'un goto
    rende le code plus propre. C'est le cas, par exemple, des sorties
    de boucles imbriqu�es en cas d'erreur.
    Cela rejoint le cas plus g�n�ral des gestions d'exceptions
    internes.

    
    Poser comme r�gle de ne jamais utiliser les
    goto est une absurdit�.
    Par contre, avertir le programmeur de l'utiliser avec parcimonie,
    et avec beaucoup de pr�cautions me semble une bonne chose.


15.8 Pourquoi commenter un #endif ?

    #endif ne peut �tre suivi par autre chose qu'un
    commentaire. On commente donc
    pour savoir � quelle directive il correspond :

    
    #if FOO
    /* du code ou des directives */
    #ifdef BAR
    /* encore du code ou des directives */
    #endif /* BAR */
    /* encore du code ou des directives */
    #endif /* FOO */
    

15.9 O� trouver de la doc sur les diff�rents styles ?

    Le document suivant contient des r�gles de base � suivre pour
    programmer proprement :
    <ftp://ftp.laas.fr/pub/ii/matthieu/c-superflu/c-superflu.pdf>

    
    Sachez �galement qu'il existe un programme indent
    issu de BSD qui r�indente automatiquement du code,
    suivant un style donn�. Les options classiques de la version
    GNU de cet utilitaire sont -kr (pour le
    style d�crit dans K&R), -gnu (pour le
    style utilis� dans les projets GNU) ou encore
    -orig (pour le style BSD).

    
    Sous Unix, on trouve �galement la commande 
    cb avec l'option -sj pour avoir le style 
    K&R.


15.10 Comment bien structurer son programme ?


    Il n'y a pas de r�ponse d�finitive, mais voici une piste :

    
     -  Suite � l'analyse (conception) il est possible de d�couper
    le projet en une multitude de syst�mes et de sous-syst�mes.

     -  Chaque sous-syst�me fait l'objet d'un module compos� d'un
    fichier source(xxx.c) et d'un fichier d'en-t�te (xxx.h).

     -  Les syst�mes sont organis�s hi�rarchiquement (arbre) de
    fa�on � �viter les d�pendences crois�es.
    

    Evidement, tout �a est peu th�orique. De plus, il existes des
    techniques avanc�es (ADT, callback) qui permettent les appels
    crois�s propres. (c � d sans d�pendances crois�es). L'avantage est
    que chaque module est testable individuellement (et le plus
    souvent r�utilisable).

    
    La phase suivante du d�veloppement est l'int�gration. Elle consiste
    � mettre la colle qui va bien pour faire tenir tout les modules
    ensembles et � tester le fonctionnement de l'ensemble.

    
    Nous ne traitons pas ici des diff�rentes m�thodes d'analyse et de
    conception. Rappelons toutefois les 5 phases (en 'V') de
    d�veloppement d'un projet : 

    
    1 - Sp�cification      5 - Validation
     \                    /
      2 - Conception    4 - Integration
       \               /
        3 - Codage et test unitaire
    

    Voir � ce sujet les questions 9.3
    et 13.5.
    
    Merci � Emmanuel Delahaye pour cette r�ponse.


16. Autres


16.1 Comment rendre un programme plus rapide ?


    Il y a deux raisons possibles � la � lenteur � d'un programme.

    
    La premi�re vient de l'�criture du code lui-m�me,
    les entr�es/sorties, les allocations dynamiques,
    de nombreux appels de fonctions, des boucles, etc.
    Le programmeur a g�n�ralement peu int�r�t � modifier son code,
    tout au plus pourra-t-il remplacer les petites fonctions le plus
    souvent appel�es par des macros et tenter de limiter les
    boucles. On pourra aussi am�liorer les entr�es/sorties et les
    allocations si c'est possible. Il reste enfin les options de
    compilation sur lesquelles on peut jouer.

    
    L'autre raison vient de la complexit� th�orique des algorithmes
    utilis�s. Dans ce dernier cas, il faut chercher un meilleur
    algorithme. Cet aspect est d�velopp� par exemple dans
    <http://www.enseignement.polytechnique.fr/profs/informatique/Jean-Jacques.Levy/poly/polyx-cori-levy.ps.gz>

    
    Il existe des outils de profilage de programmes. Il
    s'agit de compiler les sources avec une biblioth�que puis de
    lancer le programme. On lance alors un lociciel associ� � la
    biblioth�que. Le r�sultat est un fichier o� est d�taill� le temps
    pass� dans chaque fonction,
    le nombre d'appels, etc. Sur Unix-like,
    le projet GNU propose gprof
    (cf. 4.6).

    
    Rappelons tout de m�me que la vitesse d'ex�cution d'un programme
    (hors probl�mes d'algorithmique) est peu souvent critique, et
    qu'il est bien plus important de fournir un code lisible.


16.2 Quelle est la diff�rence entre byte et octet ?


    L'unit� de m�moire �l�mentaire du C est le byte.
    Le byte au sens anglo-saxon et donc pas
    l'octet au sens francophone (caract�re).

    
    En fait un byte correspond � un caract�re non-sign�
    (unsigned char), lequel peut prendre plus (ou moins) de 8
    bits. En principe, en fran�ais, on parle dans ce cas de
    multiplet (et peut-�tre bient�t de
    codet) comme traduction officielle de
    byte dans ce sens.

    
    (Merci � Antoine Leca).


16.3 Peut-on faire une gestion d'exceptions en C ?


    Oui, c'est possible, en utilisant le couple
    setjmp()/longjmp().

    
    #include <stdio.h>
    #include <stdlib.h>
    #include <setjmp.h>

    jmp_buf env;

    long fact(long x) {
        long i, n;

        if (x < 0)
            longjmp(env, 1);
        for (n = 1, i = 2; i <= x; i ++)
            n *= i;
        return n;
    }

    long comb(long k, long n) {
        if (k < 0 || n < 1 || k > n)
            longjmp(env, 2);
        return fact(n) / (fact(k) * fact(n - k));
    }

    int main(int argc, char *argv[]) {
        if (argc < 3) {
            fprintf(stderr, "pas assez d'arguments\n");
            return EXIT_FAILURE;
        }
        if (setjmp(env)) {
            fprintf(stderr, "erreur de calcul\n");
            return EXIT_FAILURE;
        }
        printf("%ld\n", comb(strtol(argv[1], 0, 0),
               strtol(argv[2], 0, 0)));
        return 0;
    }
    

    Voil� un programme qui calcule le coefficient binomial des deux
    arguments ; main() appelle comb() qui
    appelle fact().
    Ces fonctions v�rifient un peu les arguments, et on voudrait
    renvoyer une erreur en cas de probl�me ; mais :

    
     -  Je renvoie d�j� le r�sultat, il faudrait qu'il y ait des
    r�sultats � impossibles � pour y coder les erreurs ; c'est le cas
    ici (le r�sultat est toujours sup�rieur ou �gal � 1) mais �a
    demande une analyse math�matique pas toujours facile.
     -  Je ne veux pas tester les codes d'erreurs � chaque
    invocation d'une fonction. Cela peut devenir lourd syntaxiquement,
    et �a consomme du temps CPU.
    

    setjmp() sauvegarde l'�tat du programme au moment de
    l'appel, et renvoie 0.
    longjmp() remplace le contenu de la pile d'ex�cution
    par la sauvegarde, et le programme se trouve � nouveau � l'endroit
    de l'appel � setjmp(). Celle-ci renvoie alors une
    valeur pass�e en param�tre de longjmp() (dans
    l'exemple, 1 pour une erreur dans fact() et
    2 pour une erreur dans comb()).

    
    La m�thode pr�sent�e ici est assez rustique. Il existe des
    m�canismes de POO [5] 
    en C bien plus �volu�s. Vous pouvez � ce sujet
    allez voir l'excellent document :
    <http://ldeniau.home.cern.ch/ldeniau/html/oopc/oopc.html>.
    Allez voir aussi le document suivant :
    <http://cern.ch/Laurent.Deniau/html/exception/exception.html>.

    Voir aussi la question 3.10.


16.4 Comment g�rer le num�ro de version de mon programme ?


    Serge Paccalin propose la chose suivante :

    
    #define STR_(a) #a
    #define STR(a)  STR_(a)
    #define VERSION 4
    printf("This is version " STR(VERSION) " of the program\n");
    

    En effet, quelque chose comme :
    
    #define STR(a) #a
    #define VERSION a
    printf("This is version " STR(VERSION) " of the program\n");
    

    fait intervenir la concat�nation des cha�nes trop t�t ce qui fait
    que le r�sultat de cette derni�re s�quence renvoie :
    
    
    This is version VERSION of the program
    

16.5 Pourquoi ne pas mettre de `_' devant les identifiants ?

    Well well well, ce n'est pas si facile.

    
    Les vrais identificateurs r�serv�s sont :

    
     -  les mots cl�s tels que if, for,
        switch, long, ...
     -  les identificateurs commen�ant par deux `_'
     -  les identificateurs commen�ant par un `_'
    suivi d'une lettre majuscule.
    

    Ensuite, il y a les headers standards et la biblioth�que. Les
    headers sont libres d'utiliser des identificateurs commen�ant par
    un `_' et suivis d'une lettre minuscule, comme `_liste', mais
    c'est pour d�finir quelque chose qui a un � file scope �,
    c'est-�-dire une port�e globale � la � translation unit � (le
    fichier source C et les fichiers qu'il inclut). Donc, globalement,
    on ne doit pas s'en servir pour d�finir quelque chose qui a ce �
    file scope �.

    
    �a veut dire quoi ? Que les choses suivantes sont interdites :

    
    typedef int _foo;
    struct _bar {
        int x;
        char * y;
    };
    void _f(void);
    

    En revanche, les choses suivantes sont autoris�es :

    
    void f(int _x[]) {
        typedef int _foo;
        struct _bar {
            int x;
            char *y;
        };
        extern void _g(void);
    }
    struct qux {
        long _truc;
    };
    

    J'attire l'attention du public �bahi sur les quatre points
    suivants :

    
     -  En d�finissant des identificateurs � port�e r�duite (bloc,
    prototype, fonction), on peut masquer des identificateurs d�finis
    par les headers standards, identificateurs qui pouvaient
    intervenir dans des macros d�finies dans lesdits headers ; comme
    toutes les fonctions standards peuvent �tre surcharg�es par des
    macros, � l'int�rieur d'un bloc o� on a jou� � d�finir un
    identificateur de type _foo, toute utilisation d'une
    facilit� fournie par un header peut d�clencher un � undefined
    behaviour � (par exemple, l'ordinateur utilise spontan�ment son
    modem pour t�l�phoner � la belle-m�re du programmeur et l'inviter
    � venir d�ner � la maison).

     -  Le extern void _g(void); explicite le fait que la
    restriction est sur le scope et pas le linkage. Bien entendu, il
    faut que la fonction _g() soit d�finie quelque part, avec
    un external linkage, ce qui ne peut pas se faire en C
    standard. Donc cette d�claration, quoique valide, doit avoir un
    pendant dans une autre translation unit, qui ne peut pas �tre
    fabriqu� de fa�on standard. Pour compl�ter, rajoutons que la
    d�finition n'a besoin d'exister que si on se sert effectivement de
    la fonction. Donc on est en fait autoris� � faire une d�claration
    inutile qui pourrait faire planter des impl�mentations non
    conformes mais courantes. How useful.

     -  Quand bien m�me on aurait le droit, rares sont les
    impl�mentations compl�tement conformes de ce point de vue. Par pur
    pragmatisme, on �vite donc de jouer avec des identificateurs
    commen�ant par un `_' suivi d'une lettre minuscule.

     -  Chaque header apporte ses propres restrictions ; par
    exemple, <ctype.h> peut d�clarer n'importe quel
    identificateur qui commence par "is" ou "to" suivi d'une lettre
    minuscule. Ces identificateurs sont r�serv�s pour ce qui est de
    l'external linkage, ce qui veut dire que m�me si on n'inclut pas
    <ctype.h>, on ne doit pas d�finir, entre autres, de
    variable globale "iszoinx" qui ne soit pas prot�g� par le mot cl�
    static.
    

16.6 � quoi peut servir un cast en (void) ?


    Il y a principalement deux utilit�s � caster une expression en
    (void).

    
    La premi�re utilisation est pour indiquer explicitement au
    compilateur qu'une valeur est ignor�e, comme au retour d'une
    fonction. 
    Par exemple, il arrive souvent d'utiliser la fonction
    printf() sans utiliser ni m�me tester la valeur de
    retour.
    Ecrire l'appel � printf() ainsi

    
    (void)printf("%s\n", "Un message � la con") ;
    

    est une mani�re de dire au compilateur, et aux lecteurs du code,
    que je sais que printf() renvoie une valeur, mais que
    j'ai d�cid� de l'ignorer. Cela peut �tre utile pour des
    utilitaires de v�rification de code, comme lint.

    
    La seconde utilisation est dans des d�finitions de macro.
    Voici un exemple :

    
    #undef the_truc
    #ifdef __TRUC__DEPENDANT__
    #  define the_truc(a) ((void)0)
    #else
    #  define the_truc(a) /* du code */
    #endif
    

    Ainsi, the_truc(a) est utilisable l� ou une expression est
    requise, comme ici :

    
    i = (the_truc(a), 5) ;
    

    Avec une d�finition de the_truc comme ceci,

    
    #  define the_truc(a) 
    

    il y aurait une erreur � la compilation.


17. En guise de conclusion

--- Hou l�...
--- J'ai �crit �a moi ?
--- Toujours est-il que � quelqu'un � l'a �crit.
    Tant pis, maintenant tu �cris la doc'.
--- Oh non !
--- Bon alors tu d�bogues.
--- Ca va, �a va, j'�cris la doc' ...
--- OK, ensuite tu d�bogues.
--- ...


---------- 
1 : Application Programming Interface     
    i.e. interface de programmation d'applications litt�ralement ;     
    autrement-dit biblioth�que.

2 : � Rectificatif technique �.

3 : � Amendement �.

4 : pour GCC par exemple, l'option -Wall active -Wmissing-prototypes     
    -Wmissing-declarations

5 : Programmation Orient� Objet
Technical Details
Message-ID: <fr.comp.lang.faq-c-4-1128246638.306772@calva.glou.org>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!fu-berlin.de!feed.ac-versailles.fr!nocworld.net!news.valadon.net!ircam.fr!fr-chartes!maintfaq

Show Full Headers
Complete Article Headers
X-Google-Thread: f9822,95e63c57e26f24d1,start
X-Google-Thread: 102e92,95e63c57e26f24d1,start
X-Google-Attributes: gidf9822,gid102e92,public
X-Google-Language: FRENCH,ASCII
From: Guillaume Rumeau <guillaume.rumeau@wanadoo.fr>
Newsgroups: fr.comp.lang.c,fr.usenet.reponses
Subject: [FAQ] fr.comp.lang.c - partie 4/4 
Supersedes: <fr.comp.lang.faq-c-4-1126950753.87641@calva.glou.org>
Followup-To: fr.comp.lang.c
Date: Sun, 2 Oct 2005 09:50:36 GMT
Organization: FCLC
Approved: fr-reponses@frmug.org
User-Agent: MaintFaq version 2.1b
Message-ID: <fr.comp.lang.faq-c-4-1128246638.306772@calva.glou.org>
Content-Type: text/plain; charset=iso-8859-15
Content-Transfer-Encoding: 8bit
Summary: Faq de fr.comp.lang.c
X-No-Productlink: yes
Lines: 1687
Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!fu-berlin.de!feed.ac-versailles.fr!nocworld.net!news.valadon.net!ircam.fr!fr-chartes!maintfaq