Uso ints não assinados para tornar meu código e sua intenção mais claros. Uma coisa que faço para me proteger contra conversões implícitas inesperadas ao fazer aritmética com os tipos assinado e não assinado é usar um atalho não assinado (normalmente 2 bytes) para minhas variáveis não assinadas. Isso é eficaz por alguns motivos:
- Quando você faz aritmética com suas variáveis curtas não assinadas e literais (que são do tipo int) ou variáveis do tipo int, isso garante que a variável não assinada seja sempre promovida a um int antes de avaliar a expressão, pois int sempre tem uma classificação mais alta que curta . Isso evita qualquer comportamento inesperado ao fazer aritmética com tipos assinados e não assinados, assumindo que o resultado da expressão se encaixe em um int assinado, é claro.
- Na maioria das vezes, as variáveis não assinadas que você está usando não excederão o valor máximo de um curto não assinado de 2 bytes (65.535)
O princípio geral é que o tipo de suas variáveis não assinadas deve ter uma classificação inferior ao tipo das variáveis assinadas para garantir a promoção para o tipo assinado. Então você não terá nenhum comportamento inesperado de estouro. Obviamente, você não pode garantir isso o tempo todo, mas (na maioria das vezes) é possível garantir isso.
Por exemplo, recentemente tive alguns para o loop algo parecido com isto:
const unsigned short cuint = 5;
for(unsigned short i=0; i<10; ++i)
{
if((i-2)%cuint == 0)
{
//Do something
}
}
O literal '2' é do tipo int. Se eu fosse um int sem sinal em vez de um curto sem sinal, na sub-expressão (i-2), 2 seria promovido a um int sem sinal (já que o int sem sinal tem uma prioridade mais alta que o sinal assinado). Se i = 0, a sub-expressão é igual a (0u-2u) = algum valor massivo devido ao estouro. A mesma idéia com i = 1. No entanto, como i é um curto não assinado, ele é promovido para o mesmo tipo que o literal '2', que é assinado int, e tudo funciona bem.
Para maior segurança: no caso raro em que a arquitetura que você está implementando causa 2 int, isso pode fazer com que os dois operandos na expressão aritmética sejam promovidos a int sem sinal no caso em que a variável curta não assinada não se encaixa no int de 2 bytes assinado, este último com um valor máximo de 32.767 <65.535. (Consulte https://stackoverflow.com/questions/17832815/c-implicit-conversion-signed-unsigned para obter mais detalhes). Para se proteger, você pode simplesmente adicionar um static_assert ao seu programa da seguinte maneira:
static_assert(sizeof(int) == 4, "int must be 4 bytes");
e não será compilado em arquiteturas onde int é 2 bytes.
for(unsigned int n = 10; n >= 0; n --)
(laços infinitamente)