{"id":42,"date":"2008-04-05T21:29:16","date_gmt":"2008-04-05T20:29:16","guid":{"rendered":"http:\/\/linux.leunen.com\/?p=42"},"modified":"2008-04-05T21:29:16","modified_gmt":"2008-04-05T20:29:16","slug":"c-constantes","status":"publish","type":"post","link":"https:\/\/www.leunen.com\/linux\/2008\/04\/c-constantes\/","title":{"rendered":"C++ &#8211; Constantes"},"content":{"rendered":"<p>Lorsque l&rsquo;on veut pr\u00e9ciser que la valeur d&rsquo;un objet ne varie pas, on peut le faire pr\u00e9c\u00e9der du mot-cl\u00e9 <em>const<\/em>.<\/p>\n<pre class=\"codesource\">\r\n<span class=\"reservedname\">const<\/span> <span class=\"reservedname\">int<\/span> i = 10;<\/pre>\n<p>L&rsquo;objet \u00e9tant constant, il doit \u00eatre initialis\u00e9 au moment de sa d\u00e9claration.<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">const<\/span> <span class=\"reservedname\">int<\/span> i;<\/pre>\n<p>Erreur i n&rsquo;est pas initialis\u00e9.<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">const<\/span> <span class=\"reservedname\">int<\/span> i = f();<\/pre>\n<p>Ok m\u00eame si la valeur d&rsquo;initialisation n&rsquo;est pas connue au moment de la compilation.<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">void<\/span> g(<span class=\"reservedname\">const<\/span> <span class=\"reservedname\">int<\/span> i)\r\n{\r\n  <span class=\"codecomment\">\/\/ garantit que i ne sera pas modifi\u00e9\r\n<\/span>  <span class=\"codecomment\">\/\/ par la fonction\r\n<\/span>}<\/pre>\n<p>Dans le cas o\u00f9 l&rsquo;objet est initialis\u00e9 avec une valeur connue au moment de la compilation, le compilateur n&rsquo;a pas besoin d&rsquo;allouer de la m\u00e9moire pour cet objet.<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">const<\/span> <span class=\"reservedname\">int<\/span> i = 10;<\/pre>\n<p>Le compilateur connait la valeur de i et remplace directement dans le code \u00e0 chaque fois que i est utilis\u00e9, i par sa valeur 10. Aucune m\u00e9moire n&rsquo;est allou\u00e9e \u00e0 i. Aucune adresse n&rsquo;existe contenant i.<br \/>\nExaminons le code assembleur produit par <em>g++<\/em> pour le petit programme suivant en le compilant avec l&rsquo;option -S (g++ -S test.cpp).<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">int<\/span> main()\r\n{\r\n  <span class=\"reservedname\">const<\/span> <span class=\"reservedname\">int<\/span> i = 10;\r\n  <span class=\"reservedname\">int<\/span> j = i;\r\n  <span class=\"reservedname\">return<\/span> 0;\r\n}<\/pre>\n<p>Le code assembleur g\u00e9n\u00e9r\u00e9 pour 1 et 2 est le suivant:<\/p>\n<pre class=\"codesource\">movl  $10, -12(%ebp)      <span class=\"codecomment\">\/\/ const int i = 10;\r\n<\/span>movl  $10, -8(%ebp)       <span class=\"codecomment\">\/\/ int j = i\r\n<\/span><\/pre>\n<p>Le compilateur attribue \u00e0 j la valeur 10 directement sans utiliser i.<\/p>\n<p>Comparons avec ce code-ci:<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">int<\/span> main()\r\n{\r\n  <span class=\"reservedname\">int<\/span> i = 10;\r\n  <span class=\"reservedname\">int<\/span> j = i;\r\n  <span class=\"reservedname\">return<\/span> 0;\r\n}<\/pre>\n<p>Le code assembleur g\u00e9n\u00e9r\u00e9 par <em>g++<\/em> est celui-ci:<\/p>\n<pre class=\"codesource\">movl  $10, -12(%ebp)    <span class=\"codecomment\">\/\/ int i = 10;\r\n<\/span>movl  -12(%ebp), %eax   <span class=\"codecomment\">\/\/ on charge eax avec la valeur de i\r\n<\/span>movl  %eax, -8(%ebp)    <span class=\"codecomment\">\/\/ on copie eax dans j\r\n<\/span><\/pre>\n<p>On remarque que ce code est moins efficace que la version avec i constant puisque le compilateur doit d&rsquo;abord charg\u00e9 un registre du processeur (eax) avec la valeur de i et ensuite copier ce registre dans j. C&rsquo;est donc plus lent et moins efficace que dans le cas de i constant.<\/p>\n<p>Donc, d\u00e9clarez vos objets constants chaque fois que possible. Vous gagnerez en vitesse, en efficacit\u00e9 et votre code sera plus s\u00fbr, le compilateur garantissant que vos objets ne pourront en aucun cas \u00eatre modifi\u00e9s (const correctness). Une constante non-d\u00e9clar\u00e9e const et modifi\u00e9e dans le code est toujours un bug difficile \u00e0 d\u00e9celer dans un code source un peu important.<\/p>\n<p><strong>Trois remarques suppl\u00e9mentaires:<\/strong><br \/>\nPremi\u00e8rement, les objets constants ont une <em>liaison interne<\/em> (internal linkage) sauf si ils sont d\u00e9clar\u00e9s <em>extern<\/em>. Cela veut dire que vous pouvez d\u00e9clarer vos objets constants dans les fichiers d&rsquo;ent\u00eate sans risque que le compilateur vous donne une erreur du type \u00ab\u00a0d\u00e9claration multiple\u00a0\u00bb, ces objets \u00e9tant locaux \u00e0 chaque fichier.<\/p>\n<p>Deuxi\u00e8mement, le mot-clef <em>const<\/em> modifie l&rsquo;objet qui est \u00e0 sa gauche. S&rsquo;il n&rsquo;y a rien \u00e0 sa gauche alors il modifie l&rsquo;objet \u00e0 sa droite. Autement dit:<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">const<\/span> string&amp; s<\/pre>\n<p>et<\/p>\n<pre class=\"codesource\">string <span class=\"reservedname\">const<\/span> &amp; s<\/pre>\n<p>sont identiques. Dans le premier cas, il n&rsquo;y a rien \u00e0 la gauche du const et donc il modifie string et s est donc une r\u00e9f\u00e9rence vers un string constant. Dans le deuxi\u00e8me cas, <em>const<\/em> modifie ce qui est \u00e0 sa gauche c&rsquo;est \u00e0 dire string et donc s est une r\u00e9f\u00e9rence vers un string constant. C&rsquo;est bien la m\u00eame signification dans les deux cas.<\/p>\n<p>Troisi\u00e8mement, examinons les fonctions suivantes:<\/p>\n<pre class=\"codesource\"><span class=\"reservedname\">void<\/span> f(string s);\r\n<span class=\"reservedname\">void<\/span> g(string&amp; s);\r\n<span class=\"reservedname\">void<\/span> h(<span class=\"reservedname\">const<\/span> string&amp; s);\r\n\r\nstring str;\r\nf(str);\r\ng(str);\r\nh(str);<\/pre>\n<p>Dans le cas de la fonction f(str), str est pass\u00e9 par valeur et s est une nouvelle instance de str. Toute modification de s dans la fonction est perdue.<br \/>\nDans g(str), s est le m\u00eame objet que str et donc toute modification de s entraine la modification de str.<br \/>\nDans h(str), s est aussi le m\u00eame objet que str mais sa modification dans la fonction n&rsquo;est pas permise parce que d\u00e9clar\u00e9 const.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lorsque l&rsquo;on veut pr\u00e9ciser que la valeur d&rsquo;un objet ne varie pas, on peut le faire pr\u00e9c\u00e9der du mot-cl\u00e9 const. const int i = 10; L&rsquo;objet \u00e9tant constant, il doit \u00eatre initialis\u00e9 au moment de sa d\u00e9claration. const int i; Erreur i n&rsquo;est pas initialis\u00e9. const int i = f(); Ok m\u00eame si la valeur [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/posts\/42"}],"collection":[{"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/comments?post=42"}],"version-history":[{"count":0,"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/posts\/42\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/media?parent=42"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/categories?post=42"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.leunen.com\/linux\/wp-json\/wp\/v2\/tags?post=42"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}