Adloun

Le masque qui déborde

Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 14 — Exploration exhaustive et retour sur trace

Énoncé

L'énumération par bits porte la précondition . Que se passe-t-il exactement pour et ? Le compilateur prévient-il ?


for (int masque = 0; masque < (1 << n); masque = masque + 1) { /* ... */ }

Corrigé

Les deux cas sont des comportements indéfinis au sens de la norme C99 : décaler un int de rangs ou plus dépasse la largeur du type. La norme n'exige rien, et le compilateur ne signale rien. Il faut donc mesurer ce que produit la machine devant soi. Compilé avec gcc -Wall -Wextra -std=c99, aucun avertissement n'est émis, et l'exécution donne :

`(1 << n)`tours de boucle
29
30
310
321

Pour , le bit de poids fort est le bit de signe : vaut INT_MIN, la condition masque &lt; (1 &lt;&lt; n) est fausse d'emblée et la boucle ne s'exécute pas une seule fois. Pour , le décalage a été fait modulo : vaut , et la boucle ne visite que le sous-ensemble vide.

Le piège est complet : aucune erreur de compilation, aucune erreur d'exécution, aucun résultat — et un programme qui rend « aucune solution » sur les instances de taille alors qu'il en trouvait à . C'est le dépassement silencieux du chapitre chap:langage-c, à un endroit où on ne le cherche pas.

La parade : écrire la borne sur un type assez large, et documenter la limite.


/* Énumère les 2^n sous-ensembles. Précondition : 0 <= n <= 62. */
assert(0 <= n && n <= 62);
for (unsigned long long masque = 0; masque < (1ULL << n); masque = masque + 1) {
    /* ... */
}

Mesuré : 1ULL &lt;&lt; 31 vaut et 1ULL &lt;&lt; 32 vaut . Cela dit, à la boucle ne finira jamais : la vraie limite reste celle de l'exercice précédent.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.