Piège pour les inattentifs : pourquoi unsigned int est une bombe à retardement ?
\n\nChaque développeur C++ rencontre tôt ou tard une situation où les nombres se comportent comme des lapins en colère — ils sautent sans cesse du positif à zéro. Il s'agit du débordement de unsigned int. Contrairement à son homologue signé (signed int), le débordement de unsigned en C++ est strictement défini par la norme — ce n'est pas un UB (comportement indéfini). Le nombre s'enroule simplement modulo 2N. Mais cela ne rend pas l'erreur moins fatale.
Imaginez : vous calculez le solde d'un compte, le nombre d'éléments dans un tableau ou le temps de fonctionnement d'un minuteur. Un débordement accidentel, et la logique de l'application s'effondre. La question du titre "How do I detect unsigned integer overflow?" a rassemblé des milliers de vues sur Stack Overflow pour une bonne raison. Analysons trois approches pour détecter le débordement : de la naïve (mais fonctionnelle) à la professionnelle.
\n\nPourquoi les vérifications standard ne fonctionnent-elles pas ?
\n\nLa première chose qui vient à l'esprit d'un débutant :
\n\nunsigned int a = UINT_MAX;\nunsigned int b = 1;\nif (a + b < a) // Vérification naïve\n std::cout << "Débordement !";\n\nCe code fonctionne, mais seulement pour l'addition. Pour la multiplication, la soustraction ou les types mixtes, la logique se brise. De plus, le compilateur peut considérer une telle vérification comme redondante et la supprimer lors de l'optimisation. Surtout si les types sont signés. Ne comptez pas sur la magie — écrivez explicitement.
\n\nApproche n°1 : Arithmétique avant l'opération (Pre-check)
\n\nLa méthode la plus fiable est de vérifier la possibilité d'un débordement avant d'effectuer l'opération. Pour l'addition de deux nombres non signés, la condition est simple :
\n\nSi a + b peut déborder, alors a > (UINT_MAX - b).
#include <climits>\n#include <iostream>\n\nbool will_add_overflow(unsigned int a, unsigned int b) {\n return a > UINT_MAX - b;\n}\n\nint main() {\n unsigned int x = 4000000000;\n unsigned int y = 500000000;\n \n if (will_add_overflow(x, y)) {\n std::cerr << "Erreur : débordement lors de l'addition !\\n";\n } else {\n std::cout << "Résultat : " << x + y << "\\n";\n }\n return 0;\n}\n\nMultiplication — plus complexe
\nPour la multiplication, la vérification est un peu plus délicate : a > UINT_MAX / b (et n'oubliez pas la division par zéro).
bool will_mult_overflow(unsigned int a, unsigned int b) {\n if (b == 0) return false; // Multiplication par zéro — sûr\n return a > UINT_MAX / b;\n}\n\nAvantages : Multiplateforme, contrôle total, aucune dépendance cachée.
\nInconvénients : Nécessité d'écrire des fonctions séparées pour chaque opération. Le code devient volumineux.
Approche n°2 : Vérification après l'opération (Post-check)
\n\nLa norme C++ garantit que pour les types unsigned, le résultat d'une opération est (a + b) mod 2^N. Par conséquent, nous pouvons effectuer l'opération, puis vérifier si la valeur a "enroulé".
#include <iostream>\n#include <limits>\n\ntemplate<typename T>\nbool add_overflow(T a, T b, T& result) {\n result = a + b;\n return result < a; // Astuce clé\n}\n\nint main() {\n unsigned int res;\n if (add_overflow(4000000000u, 500000000u, res)) {\n std::cout << "Débordement détecté !\\n";\n } else {\n std::cout << "OK : " << res << "\\n";\n }\n return 0;\n}\n\nImportant : Cette astuce fonctionne uniquement si a et b sont du même type non signé. Pour uint32_t — parfait. Pour un mélange de unsigned int et int — échec.
Piège pour la soustraction
\nPour la soustraction, la condition est inverse : result > a.
template<typename T>\