Armadilha para desatentos: por que unsigned int é uma bomba-relógio?
\n\nTodo desenvolvedor C++ mais cedo ou mais tarde se depara com uma situação em que os números se comportam como coelhos furiosos — pulam infinitamente do positivo para o zero. Estamos falando do overflow de unsigned int. Ao contrário de seu primo com sinal (signed int), o overflow de unsigned em C++ é estritamente definido pelo padrão — não é UB (comportamento indefinido). O número simplesmente é envolvido pelo módulo 2N. Mas isso não torna o erro menos fatal.
Imagine: você calcula o saldo de uma conta, a quantidade de elementos em um array ou o tempo de funcionamento de um timer. Um overflow acidental — e a lógica do aplicativo desmorona. A pergunta do título "How do I detect unsigned integer overflow?" reuniu milhares de visualizações no Stack Overflow por um bom motivo. Vamos analisar três abordagens para detecção de overflow: da ingênua (mas funcional) à profissional.
\n\nPor que as verificações padrão não funcionam?
\n\nA primeira coisa que vem à mente de um iniciante:
\n\nunsigned int a = UINT_MAX;\nunsigned int b = 1;\nif (a + b < a) // Verificação ingênua\n std::cout << "Overflow!";\n\nEste código funciona, mas apenas para adição. Para multiplicação, subtração ou tipos mistos, a lógica quebra. Além disso, o compilador pode considerar essa verificação redundante e removê-la durante a otimização. Especialmente se os tipos forem com sinal. Não confie em mágica — escreva explicitamente.
\n\nAbordagem nº1: Aritmética antes da operação (Pre-check)
\n\nA maneira mais confiável é verificar a possibilidade de overflow antes de realizar a operação. Para a soma de dois números sem sinal, a condição é simples:
\n\nSe a + b pode causar overflow, então 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 << "Erro: overflow na adição!\\n";\n } else {\n std::cout << "Resultado: " << x + y << "\\n";\n }\n return 0;\n}\n\nMultiplicação — mais complexa
\nPara multiplicação, a verificação é um pouco mais complicada: a > UINT_MAX / b (e não se esqueça da divisão por zero).
bool will_mult_overflow(unsigned int a, unsigned int b) {\n if (b == 0) return false; // Multiplicação por zero — segura\n return a > UINT_MAX / b;\n}\n\nPrós: Multiplataforma, controle total, sem dependências ocultas.
\nContras: É necessário escrever funções separadas para cada operação. O código se torna volumoso.
Abordagem nº2: Verificação após a operação (Post-check)
\n\nO padrão C++ garante que, para tipos unsigned, o resultado da operação é (a + b) mod 2^N. Portanto, podemos realizar a operação e depois verificar se o valor "envolveu".
#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; // Truque chave\n}\n\nint main() {\n unsigned int res;\n if (add_overflow(4000000000u, 500000000u, res)) {\n std::cout << "Overflow detectado!\\n";\n } else {\n std::cout << "OK: " << res << "\\n";\n }\n return 0;\n}\n\nImportante: Este truque funciona apenas se a e b forem do mesmo tipo sem sinal. Para uint32_t — funciona perfeitamente. Para uma mistura de unsigned int e int — falha.
Armadilha para subtração
\nPara subtração, a condição é inversa: result > a.
template<typename T>\