No último fim de semana eu lancei um desafio de C# no Twitter. A pergunta era: nesse código, como é possível que a primeira soma não dê overflow, enquanto a segunda dá?
checked { var y = n + 5; WriteLine(y); var x = m + 5; WriteLine(x); }
Pense um pouco sobre a pergunta, abaixo vou colocar algumas opções de como resolver o enigma. Role a tela para ver a explicação.
.
.
.
.
.
.
.
.
.
O primeiro ponto a considerar é o contexto “checked”, que não é padrão no C#. Por padrão, após superar o valor máximo, o variável “dá a volta” e vai até o valor mínimo.
WriteLine("Is int.MaxValue + 1 == int.MinValue? " + (m + 1 == int.MinValue)); // output: Is int.MaxValue + 1 == int.MinValue? True
Se você colocar o código acima em um bloco “checked”, uma “OverflowException” será lançada.
Então, como resolver?
Alguns outros números funcionam um pouco diferente. Por padrão, os números de ponto flutuante (fload e double) não tem esse comportamento, então essa é uma opção válida:
var m = int.MaxValue; var n = float.MaxValue; // ou double.MaxValue checked { var y = n + 5; WriteLine(y); var x = m + 5; WriteLine(x); }
E “decimal”? Decimal é também ponto flutuante, mas funciona como os inteiros, também dá overflow.
Mas existe um inteiro que não dá overflow, e esse era o tipo que eu estava pensando quando fiz o desafio. É o IntPtr, que tem o tamanho nativo de um inteiro no sistema em que está rodando, e por isso é usado muito para ponteiros e HWDs. Eles também não geram a exception:
var m = int.MaxValue; var n = IntPtr.MaxValue; checked { var y = n + 5; WriteLine(y); var x = m + 5; WriteLine(x); }
Isso quer dizer que todo inteiro nativo é assim? E os novos tipos de inteiro nativos, “nint” e “nuint”?
Esses dois tipos foram criados para ficarem mais alinhados ao comportamento do sistema de inteiros do .NET, enquanto possuem o tamanho do sistema nativo (ou seja, assim como IntPtr, variam de acordo com a arquitetura, 32 ou 64 bits). Ou seja, causam uma exception caso tenham overflow num contexto “checked”.
Coloquei mais alguns exemplos em um Gist, caso queiram ver. É só rodar.
Você pode acessar o .NET Fiddle aqui, e fiz um Gist também, aqui.
Obrigado a todos se divertiram comigo no fim de semana, e se você tiver outras formas de resolver, comenta aqui no blog!