Capturando overflow de unsigned int: Detetive C++ do zero ao profissional

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Armadilha para desatentos: por que unsigned int é uma bomba-relógio?

\n\n

Todo 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.

\n\n

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\n

Por que as verificações padrão não funcionam?

\n\n

A primeira coisa que vem à mente de um iniciante:

\n\n
unsigned int a = UINT_MAX;\nunsigned int b = 1;\nif (a + b < a) // Verificação ingênua\n    std::cout << "Overflow!";
\n\n

Este 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\n

Abordagem nº1: Aritmética antes da operação (Pre-check)

\n\n

A 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\n

Se a + b pode causar overflow, então a > (UINT_MAX - b).

\n\n
#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\n

Multiplicação — mais complexa

\n

Para multiplicação, a verificação é um pouco mais complicada: a > UINT_MAX / b (e não se esqueça da divisão por zero).

\n\n
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\n

Pró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.

\n\n

Abordagem nº2: Verificação após a operação (Post-check)

\n\n

O 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".

\n\n
#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\n

Importante: 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.

\n\n

Armadilha para subtração

\n

Para subtração, a condição é inversa: result > a.

\n\n
template<typename T>\                

Blogs

Book Recommendations