home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 17 / CD_ASCQ_17_101194.iso / dos / prg / alb_c10 / chap_07 / chap_07.txt < prev    next >
Encoding:
Text File  |  1994-10-03  |  17.0 KB  |  356 lines

  1.  
  2. ==========================================================================
  3.                              APPRENTISSAGE du C             version ALB_10                
  4.                              
  5.                   CHAPITRE 7: DES DIRECTIVES ET DES MACROS.                   
  6. ==========================================================================
  7.  
  8.  
  9.       Nous avons déjà mentionné les trois phases de la fabrication d'un
  10.    programme:
  11.                 l'écriture du code source,
  12.                 la compilation, 
  13.                 la création de liens entre les différentes parties.
  14.    
  15.       Nous allons nous intéresser à la seconde phase. Il existe en C un 
  16.    ensemble de directives qui permettent de donner des instructions au 
  17.    compilateur. Nous en avons déjà rencontré deux, #include et #define. 
  18.    Nous allons étudier, plus en détails, les principales d'entre elles.
  19.  
  20.       Elles commencent avec le symbole # et doivent être calées à gauche de 
  21.    votre texte. Le reste de la ligne doit rester vide, sauf le code /* qui 
  22.    permet des commentaires. Si la directive prend plus d'une ligne, il faut 
  23.    utiliser le symbole \ avant de passer à la ligne  suivante.
  24.  
  25.  
  26.                 1. INSERER DU TEXTE AVEC LA DIRECTIVE #include.
  27.                 ================================================
  28.  
  29.       Nous avons déjà utilisé cette directive pour appeler des fichiers 
  30.    contenant des librairies standards. Le compilateur inclut le texte du
  31.    fichier dans notre code. Il est allé le chercher dans le répertoire 
  32.    standard des fichiers "include". Par exemple: c:\tcwin\include
  33.  
  34.       Vous pouvez vous même créer un fichier qui contienne vos propres
  35.    fonctions, par exemple fonction.h, et l'appeler dans votre programme.
  36.  
  37. #include"fonction.h"       /* avec cette fois ci des guillemets anglais.*/
  38.  
  39.       Le compilateur cherchera ce fichier dans le répertoire standard où 
  40.    vous pouvez placer votre fichier de fonctions. S'il ne l'y trouve pas, il
  41.    cherchera dans le répertoire courant, qui est celui à partir duquel on a 
  42.    appelé le compilateur, et qui en général est celui de votre programme.
  43.    Mais il est plus prudent d'indiquer le chemin complet du fichier.
  44.   Chapitre 7: Des directives et des macros                          page 1
  45.  
  46.  
  47.  
  48.  
  49.         2. REMPLACER UNE CHAINE DE CARACTERES AVEC LA DIRECTIVE #DEFINE.
  50.         =================================================================
  51.  
  52. #define identificateur Chaîne de caractères 
  53.  
  54.       La chaîne commence après le premier espace qui suit l'identificateur.
  55.    Le compilateur remplacera dans tout le code, l'identificateur par la 
  56.    chaîne. On trouve à cette directive plusieurs utilisations.
  57.  
  58.    2.1. Remplacement d'une constante ou d'un texte.
  59.    ------------------------------------------------
  60.    =>  Exemple n°1:
  61.  
  62. #define dim 16          // définit la dimension de chaînes de caractères ou
  63.                         // de tableaux.
  64. void main( void)
  65. {
  66.         char chaine0[dim], chaine1[dim* 2];
  67.         double tableau[dim- 1];
  68.         ...
  69. }
  70.       L'identificateur dim sera remplacé par sa valeur. Si par la suite nous
  71.    devons modifier la dimension de notre chaîne, nous n'aurons à changer que
  72.    la valeur de la constante.
  73.  
  74.    =>  Exemple n°2:
  75. #define PI 3.14159265358979323846 
  76. #define C 0.5772156649 // constante d'Euler, mathématicien suisse(1707- 1783).
  77.  
  78.       Dans tout notre code les identificateurs PI ou C seront remplacés par 
  79.    les valeurs de ces constantes.
  80.                                                                 ************
  81.                                  Examinez les fichiers:           CH07_01.C
  82.                                                                   CH07_02.C
  83.                                                                 ************
  84.       Vous pouvez ainsi vous constituer un fichier de constantes, l'appeler
  85.    par exemple ctes.h, le placer dans le sous répertoire "include" et 
  86.    l'appeller comme une bibliothèque standard:  
  87.    
  88.                 #include<ctes.h> ou mieux #include"ctes.h". 
  89.                 
  90.    Vous pouvez aussi le placer dans le même répertoire que CH07_02.C, mais 
  91.    par prudence il vaudra mieux appeler le fichier avec son chemin d'accès
  92.    complet:
  93.                 #include"c:\albulus\chap_07\ctes.h"
  94.     
  95.    ( Si vous avez placé le manuel dans un répertoire nommé albulus).
  96.  
  97.    Pour afficher avec printf() des réels en notation dite scientifique, on
  98.    utilise le symbole %le ou %lE au lieu de %lf.
  99.  
  100.    => Remarque: nous avons déjà plusieurs constantes à notre disposition par
  101.       exemple dans le fichier math.h que nous avons utilisé pour sa 
  102.       bibliothèque de fonctions mathématiques. Appelez ce fichier sur votre 
  103.       éditeur. A la fin du fichier vous trouverez une série de constantes que 
  104.       vous pouvez utiliser directement SI VOUS ETES EN C++. 
  105.   Chapitre 7: Des directives et des macros                          page 2
  106.  
  107.  
  108.  
  109. /* Constantes arrondies à 21 decimales dans math.h et seulement en C++. */
  110. #define M_E         2.71828182845904523536
  111. #define M_LOG2E     1.44269504088896340736
  112. #define M_LOG10E    0.434294481903251827651
  113. #define M_LN2       0.693147180559945309417
  114. #define M_LN10      2.30258509299404568402
  115. #define M_PI        3.14159265358979323846
  116. #define M_PI_2      1.57079632679489661923
  117. #define M_PI_4      0.785398163397448309616
  118. #define M_1_PI      0.318309886183790671538
  119. #define M_2_PI      0.636619772367581343076
  120. #define M_1_SQRTPI  0.564189583547756286948
  121. #define M_2_SQRTPI  1.12837916709551257390
  122. #define M_SQRT2     1.41421356237309504880
  123. #define M_SQRT_2    0.707106781186547524401
  124.  
  125.    2.2. Macro-instructions.
  126.    ------------------------
  127.  
  128.                         2.2.1. Généralités.
  129.  
  130.       Il est possible de remplacer l'identificateur par ce qui ressemble 
  131.    fort à une définition de fonction avec un nom et des arguments. 
  132.    Le texte de remplacement sera une quasi définition de fonction.
  133.  
  134. #define nom_de_la_macro( arguments)  définition de la macro
  135.  
  136.    La macro se place en général en tête, avant les définitions de fonctions.
  137.    Sa portée s'exerce du point où elle se trouve à la fin du fichier qui la
  138.    limite. La parenthèse qui ouvre la liste des arguments doit suivre le nom
  139.    de la macro, sans espace ni tabulation.
  140.    On peut limiter sa portée en incluant à l'endroit désiré une directive
  141.    #undef nom_de_la_macro. La définition est annulée pour la suite du code.
  142.    
  143.                         2.2.2. Macros et fonctions.
  144.  
  145.    *  Pourquoi substituer une macro à une fonction classique?
  146.    Parce que la gestion d'une fonction est lourde, réservation d'une zone de
  147.    mémoire, création de nouvelles variables,...
  148.    Dans le cas d'une macro, le compilateur remplace directement dans le code
  149.    l'argument par sa définition. C'est plus rapide. 
  150.    
  151.    L'usage d'une macro à la place d'une fonction se justifie pour des 
  152.    applications qui utilisent un petit nombre de fonctions et en particulier 
  153.    pour celles qui appellent une fonction dans une boucle.
  154.  
  155.    *  Mais:
  156.       1° Un contrôle est fait sur le nombre d'arguments mais pas sur leur
  157.          type. Pour une fonction le compilateur détecte cette erreur .
  158.       2° Le nom d'une fonction est associé à une adresse. Une fonction peut 
  159.          donc appeler une autre fonction, ce qui n'est pas possible pour une
  160.          macro.
  161.       3° Il se produit parfois,quand on fait appel à des arguments, ce que 
  162.          l'on nomme des "effets de bords". Ce sont souvent des conflits non 
  163.          résolus entre plusieurs définitions. Les erreurs sont parfois très
  164.          délicates à identifier. Nous en étudierons un cas.
  165.   Chapitre 7: Des directives et des macros                          page 3
  166.  
  167.  
  168.  
  169.                         2.2.3. Exemples.
  170.                                                                 ************
  171.                                    Examinez le fichier:           CH07_03.C
  172.                                                                 ************
  173.      Ces macros ont été écrites par des développeurs réputés: Wayne Hamilton,
  174.    Dave Knapp et Thad Smith que nous connaissons déjà. Remarquez que les 
  175.    variables sont toujours soigneusement mises entre parenthèses dans les
  176.    définitions elles mêmes entre parenthèses.
  177.  
  178.       Les fonctions contenues dans les bibliothèques sont accessibles pour
  179.    les macros. C'est logique puisque les macros sont en fait dans le corps de 
  180.    la fonction principale où elles ont été recopiées par le compilateur. 
  181.    Nous remarquons l'utilisation de trois fonctions de la bibliothèque math.h:
  182.  
  183.         double floor( double x) donne l'arrondi par défaut, 
  184.         l'arrondi par excès est donné par ceil().
  185.         atan( x) donne l'Arc tangente et nous connaissons pow( x, y).
  186.  
  187.      Il y a une définition simple de PI à partir d'un cas particulier, comme
  188.    souvent en calcul numérique. Le calcul de atan() ne se fait certainement 
  189.    pas avec la série à convergence lente que nous avons étudié. Notez que 
  190.    l'utilisation de la macro n'évite pas dans ce cas l'appel à math.h.
  191.    Analysez la macro fround( n, d), c'est simple et élégant. Il semble qu'il 
  192.    n'y ait pas une lettre de trop.
  193.                                                                 ************
  194.                                    Examinez le fichier:           CH07_04.C
  195.                                                                 ************
  196.  
  197.       C'est un exemple type d'utilisation de macros. Max et Min sont courtes,
  198.    inscrites une seule fois dans le code et incluses dans une boucle. 
  199.       La macro Produit est très simple. Elle a été ajoutée pour montrer que
  200.    la substitution de texte ne se fait pas à l'intérieur d'une chaîne:
  201.         i*j n'a pas remplacé Produit dans "n i= %d , j= %d , Produit= %d"
  202.  
  203.    Dans ce cas le programme doit être plus rapide qu'en faisant appel à une 
  204.    fonction. Essayez de le vérifier avec le procédé utilisé dans CH06_04.C.
  205.    Ecrivez la fonction équivalente. Donnez à "Fin" la valeur 30000. Supprimez
  206.    la ligne d'impression dans la boucle. 
  207.  
  208.                                                                 ************
  209.                                    Contrôlez vous avec:           CH07_05.C
  210.                                                                 ************
  211.                                    Examinez le fichier:           CH07_06.C
  212.                                                                 ************
  213.    1° La première ligne d'affichage montre la nécessité des parenthèses.
  214.    
  215.         Produit1( a+ 1, b+ 1)= ( 2+ 1 * 2+ 1  +  3+ 1 * 3+ 1)= 12
  216.  
  217.         Produit2( a+ 1, b+ 1)= ( (2+ 1)*( 2+ 1) + (3+ 1)*( 3+ 1))= 25
  218.         qui est bien le résultat que nous attendions.
  219.  
  220.    2° La seconde donne un exemple d'effet de bords. On comprend encore que: 
  221.    
  222.         Produit2( a++, b++)= ( 2*( 2+ 1) + 3* (3+ 1) )= 18
  223.  
  224.       mais je n'ai pas trouvé pour ma part d'explication satisfaisante à:
  225.  
  226.         Produit2( a+ 1, b+ 1)= 61!!!! 
  227.         peut être: 61= 5* 5 + 6* 6 avec un effet de l'incrémentation qui 
  228.         suit? Si vous avez une explication convaincante, écrivez moi.
  229.   Chapitre 7: Des directives et des macros                          page 4
  230.  
  231.  
  232.  
  233.       Une conclusion possible est de n'employer les macros: 
  234.       
  235.    ========================================================================
  236.         => que lorsque la vitesse d'exécution est le critère principal. 
  237.         
  238.         => et de toujours rechercher une extrème simplicité du code pour 
  239.            éviter des effets de bords difficiles à maîtriser.
  240.    ========================================================================
  241.  
  242.  
  243. From: JOSEPH CARNAGE                  
  244. City: DUNEDIN FL                   
  245.  --  Never EVER pass a #defined macro an incremented or decremented
  246.       value (++,or  --) or an assignment as a parameter.  This is because 
  247.       many #defined macros may reference their arguments multiple times.  
  248.       This is especially true of the macros #defined in ctype.h.
  249.                 #define iscsymf(c)   (isalpha(c) || ((c) == '_'))
  250.       if called as so:
  251.                 iscsym(var++);
  252.       it will be expanded by the preprocessor to:
  253.                 (isalpha(var++) || ((var++) == '_'))
  254.       with var being incremented twice.
  255.  
  256.    
  257.                     2.2.4. Une macro peut utiliser des types 
  258.                              différents de variables.
  259.  
  260.       Nous avions noté, pour en souligner le danger, qu'une macro ne 
  261.    vérifiait pas le type de ses arguments.
  262.       C'est aussi la seule méthode en C actuel qui permette d'écrire de 
  263.    pseudo fonctions pouvant utiliser des types différents de variables.
  264.  
  265.                                                                 ************
  266.                                     Etudiez le fichier:           CH07_07.C
  267.                                                                 ************
  268.  
  269.    1° La macro calcule la valeur actuelle Vo d'une somme V au taux de t pour
  270.    une durée de n années, soit Vo= V* (1+ t/100)^(-n). Elle s'écrit sur
  271.    plusieurs lignes avec le symbole "\" et respecte l'intervalle entre 
  272.    l'identificateur et le symbole "{" qui marque le début de la déclaration.
  273.    Nous avons mis des parenthèses là où elles paraissent indispensables. Dans
  274.    une application nous en aurions mis partout!
  275.  
  276.         i= ( (t)/100);
  277.         Vo= ( (S)*(pow( ( 1+(i)), (- n)));   // prudence ou pusillanimité!
  278.  
  279.    2° La macro utilise trois variables qui lui sont passées et deux variables 
  280.    i et Vo qui seront déclarées dans le corps du programme principal. Nous 
  281.    avons défini pour ces deux variables le type le plus long compatible avec 
  282.    la conversion automatique des types que fait notre compilateur.
  283.  
  284.    3° L'intérêt du programme est qu'il montre qu'il est possible d'utiliser
  285.    la même macro pour traiter des variables de type float et double. Nous
  286.    savons que cela n'est pas possible avec des fonctions. 
  287.    En C++, pour répondre aux besoins des programmeurs, les développeurs ont 
  288.    conçu le concept de "template" qui permet d'utiliser des fonctions 
  289.    ( et des classes) de types différents.
  290.   Chapitre 7: Des directives et des macros                          page 5
  291.  
  292.  
  293.  
  294.    4° Notez deux petites choses: 
  295.      => la manière de faire afficher par printf() le symbole %,
  296.         printf("... %% ...)
  297.         le premier est interprété comme le début d'un groupe de caractères
  298.         qui indiquent un champ, le second comme un caractère à afficher.
  299.      => La valeur que nous avons attribué à somme_f n'a pas été prise en 
  300.         compte par la variable de type float à partir du huitième chiffre.
  301.         L'erreur que nous constatons sur Vo, lors du calcul en float en est 
  302.         la conséquence directe.
  303.  
  304.  
  305.                     2.2.5. Les directives de compilation 
  306.                              sous conditions.
  307.  
  308.       Ce sont #if, #else, #elif (équivalent de else if), #ifdef et #ifndef 
  309.    qui permettent de savoir si une macro ou une constante ont dèjà été 
  310.    définies, #endif qui termine obligatoirement une boucle où figure if.
  311.       Nous en avons vu des exemples dans CH07_03.C et ctes.h. Cela permettait
  312.    d'éviter une double définition dans le cas d'une utilisation simultanée 
  313.    de plusieurs fichiers dans le même programme.
  314.  
  315.    #ifndef PI                // si Pi n'a pas été défini ailleurs,
  316.    #define PI (4*atan(1))    // nous le définissons ici.
  317.    #endif                    // fin de la boucle if.
  318.  
  319.  
  320.                 2.2.6. Les opérateurs de substitution de chaîne # 
  321.                           et de fusion d'éléments avec ##.
  322.                                                                 ************
  323.                                     Etudiez le fichier:           CH07_08.C
  324.                                                                 ************
  325.    1° Dans la première macro, l'opérateur # entre les parenthèses de 
  326.       printf(), permet de convertir l'argument en une chaîne. 
  327.       Notez certaines particularités, une série d'espacements est réduite à 
  328.       un seul, tous les caractères ne peuvent être pris en compte. 
  329.  
  330.    2° Dans la seconde nous utilisons également l'opérateur de fusion qui 
  331.       permet de fusionner deux éléments si ceux-ci sont séparés par ##. On
  332.       peut ajouter comme dans l'exemple un espace de part et d'autre des ##.
  333.       L'espace et les ## sont supprimés et les éléments de part et d'autre 
  334.       fusionnés. Nous aurons en fait dans le code:
  335.  
  336.            printf("\n La variable est: Z5= %d\n", Z5) 
  337.  
  338.                 2.2.7. La directive #pragma.
  339.  
  340.       Son utilisation dépend du compilateur que vous utilisez. Consultez
  341.    votre documentation.
  342.  
  343.         #pragma nom_ de_la _directive
  344.  
  345.    Parmi ceux qui sont utilisés par les compilateurs de Borland:
  346.  
  347.    => #pragma exit et #pragma startup qui permettent d'indiquer au programme
  348.       que des fonctions doivent être appelées lors du lancement, avant 
  349.       l'appel de main() ou juste avant la fin.
  350.    => #pragma hdrfile et #pragma hdrstop qui facilitent la gestion des 
  351.       fichiers d'en-tête.
  352.    => #pragma inline permet l'insertion de code en assembleur.
  353.   Fin du chapitre 7: Des directives et des macros                   page 6
  354.  
  355.  
  356.