Quais são os casos em que os tipos de dados 'uint' e 'short' são mais adequados que o padrão int (32)?


24

Entendo as diferenças de capacidade e valores que eles podem representar, mas parece que as pessoas sempre usam Int32independentemente de ser apropriado. Parece que ninguém usa a versão não assinada ( uint), mesmo que na maior parte do tempo ela se encaixe melhor, pois descreve um valor que não pode ser negativo (talvez para representar um ID de um registro de banco de dados). Além disso, ninguém parece usar, short/Int16independentemente da capacidade exigida do valor.

Objetivamente, existem casos em que é melhor usar uintou, em short/Int16caso afirmativo, quais são?


13
A popularidade nem sempre é uma métrica viável para avaliar as decisões de design de software. Só porque uma prática é popular, não significa que seja uma prática apropriada para o seu aplicativo em particular ou que seja uma boa prática.
Robert Harvey


11
A resposta curta, eu acho, é que os programadores se acostumaram com a semântica assinada e estão inclinados a assumi-las, mesmo quando lidam com tipos não assinados (e, portanto, semântica não assinada). A maioria das pessoas assume que é uma questão de o programador ser preguiçoso ou sem instrução, mas o programador em questão pode, de fato, ser muito educado e muito cuidadoso e deseja evitar armadilhas sutis. Se desejar, consulte soundsoftware.ac.uk/c-pitfall-unsigned e anteru.net/2010/05/17/736 .
Theodoros Chatzigiannakis

Em um número não assinado, o sinal é mais do nullque positivo ou negativo. Se você pensar nisso como algo que nunca pode ser negativo ou sempre positivo, você ficará surpreso (e geralmente com raiva) com os resultados, porque realmente não funciona dessa maneira, especialmente quando comparado ou subtraído a / de valores assinados.
Adam D. Ruppe

11
Na minha experiência, muitos programadores, que já programaram em linguagem C, tendem a se importar com bytes, ainda hoje em dia, de GBs de memória e espaço de armazenamento.
user1451111

Respostas:


25

Eu suspeito que você está se referindo a uma perspectiva colorida por suas próprias experiências, na qual você não trabalhou com pessoas que usam tipos integrais corretamente. Isso pode muito bem ser uma ocorrência comum, mas tem sido minha experiência que as pessoas geralmente as usam corretamente também.

O benefício é o espaço na memória e o tempo da CPU, possivelmente o espaço de E / S, dependendo de os tipos serem enviados pela conexão ou para um disco. Os tipos não assinados fornecem verificações do compilador para garantir que você não realize determinadas operações impossíveis, além de estender o intervalo disponível, mantendo o tamanho menor para aumentar o desempenho onde for necessário.

O uso correto é o que você esperaria - a qualquer momento que você tenha certeza, poderá usá-lo permanentemente (não o restrinja sem segurança ou você se arrependerá mais tarde).

  • Se você estiver tentando representar algo que nunca poderia ser razoavelmente negativo ( public uint NumberOfPeople), use um tipo não assinado.
  • Se você está tentando representar algo que nunca poderia ser razoavelmente maior que 255 ( public byte DamagedToothCount), use um byte.
  • Se você estiver tentando representar algo que possa ser razoavelmente maior que 255, mas nunca um número significativo de milhares , use um pequeno ( public short JimmyHoffasBankBalance).
  • Se você está tentando representar algo que pode ter muitas centenas de milhares, milhões, mas é improvável que chegue a vários bilhões, use um int ( public int HoursSinceUnixEpoch).
  • Se você sabe com certeza que esse número pode ter um valor ilimitado ou acha que pode ter vários bilhões, mas não sabe ao certo quantos bilhões, a sua melhor aposta é longa. Se o tempo não for grande o suficiente, você terá um problema interessante e precisará começar a analisar números de precisão arbitrários ( public long MyReallyGreatAppsUserCountThisIsNotWishfulThinkingAtAll).

Esse raciocínio pode ser usado na escolha entre tamanhos assinados, não assinados e variados de tipos e outros, basta pensar nas verdades lógicas dos dados que você está representando na realidade.


11
+1, embora eu tenha que deixar claro que os “números de telefone” não são números, mas cadeias de dígitos e formatação opcional. Você parece estar ciente disso, mas não queremos dar um mau exemplo, agora? Além disso, restringir arbitrariamente a faixa de algum valor é um antipadrão de míope - em intqualquer lugar, a menos que você saiba que o domínio do problema realmente restringe o valor - nenhum banco gostaria de limitar as contas a 33 mil libras (e pense na diversão quando isso transborda ...!).
amon

3
Nova meta de vida: um saque a descoberto considerável que invade o tipo integral da minha conta bancária.
Recursion.ninja #

11
Existem boas razões para não usar tipos não assinados em determinados locais, por exemplo, quando a aritmética é misturada entre assinado e não assinado. Consulte Quais são as práticas recomendadas para ints não assinados? .

19
Eu discordo do raciocínio aqui. Tipos não assinados geralmente são um erro devido à subtração e comparações serem inesperadas se você estiver acostumado a ints (eles funcionam de maneira consistente, mas nem sempre é "positivo"). Eu os evitaria a menos que você tenha um motivo muito específico para usá-los. Além disso, por que o tamanho é importante para byte x curto x int? Muitas vezes, você nem economiza espaço, pois as estruturas mantêm esses membros ou matrizes em um certo alinhamento. Eu usaria um byte apenas se o tamanho for realmente importante (improvável especialmente para o código C # que eu já vi) ou se você desejar especificamente uma envolvente em 255 para alguma coisa.
Adam D. Ruppe

4
"benefício é espaço de memória e tempo de CPU" ... não vejo nenhum caso em que tipos minúsculos realmente economizassem tempo de CPU. Operações inteiras nunca ficam mais rápidas do que nos tipos de tamanho de máquina , ou seja, no que diz respeito à CPU, você também pode usar long. É claro que a economia de memória economiza tempo indiretamente, melhorando a eficiência da linha de cache e assim por diante, mas OTOH os problemas de alinhamento com tipos pequenos podem indiretamente custar tempo.
usar o seguinte comando

16

Claro, há casos em que é melhor usar uintou shortou Int16. Quando você souber que seu intervalo de dados se ajustará às restrições desse tipo de variável, não há problema em usá-lo.

Em ambientes com restrição de memória ou ao lidar com grandes quantidades de objetos, pode fazer sentido usar a menor variável de tamanho. Por exemplo, há uma diferença significativa no tamanho para uma matriz de milhões de elementos de ints vs. shorts.

Muitas vezes, isso não acontece no código real por um ou mais dos seguintes motivos:

  • As restrições de dados não eram conhecidas antecipadamente
  • Havia uma chance de que as restrições de dados não fossem sólidas ou que provavelmente seriam alteradas
  • Havia a esperança de reutilizar a função com um intervalo de dados mais amplo
  • O desenvolvedor não teve tempo para pensar nas restrições
  • A economia de memória foi insignificante para justificar o uso de um tipo de variável menor

Há muito mais razões possíveis, mas elas se resumem a isso: o tempo envolvido na decisão e no uso de um tipo de variável diferente não forneceu benefícios suficientes para justificar isso.


8

Em C, em contextos que não envolvem promoção inteira , valores não assinados foram especificados para se comportarem como membros de um anel algébrico abstrato "empacotado" (portanto, para qualquer X e Y, XY produzirá um valor exclusivo que, quando adicionado a Y, produzirá X ), enquanto tipos de números inteiros assinados foram especificados como se comportando como números inteiros quando os cálculos permaneceram dentro de um determinado intervalo e permitiram fazer qualquer coisa quando os cálculos foram além disso. A semântica numérica em C #, no entanto, é totalmente diferente. Quando em um contexto numérico verificado, os tipos assinado e não assinado se comportam como números inteiros, desde que os cálculos fiquem dentro do alcance e sejam lançados OverflowExceptionquando não o fazem; em um contexto não verificado, ambos se comportam como anéis algébricos.

Geralmente, é o único momento em que vale a pena usar qualquer tipo de dados menor do Int32que o necessário para empacotar ou descompactar itens para armazenamento ou transporte compacto. Se for necessário armazenar meio bilhão de números positivos, e todos eles estarão no intervalo de 0 a 100, usar um byte cada em vez de quatro economizará 1,5 gigabytes de armazenamento. Isso é uma grande economia. Se um pedaço de código precisar armazenar um total de algumas centenas de valores, no entanto, transformar cada um em um byte em vez de quatro economizaria cerca de 600 bytes. Provavelmente não vale a pena se preocupar.

No que diz respeito aos tipos não assinados, as únicas vezes em que são realmente úteis são na troca de informações ou na subdivisão de números em partes. Se, por exemplo, for necessário fazer cálculos em números inteiros de 96 bits, provavelmente será muito mais fácil executar os cálculos em grupos de três números inteiros de 32 bits não assinados do que em grupos de números inteiros assinados. Caso contrário, não há muitas situações em que o intervalo de um valor assinado de 32 ou 64 bits seria inadequado, mas o mesmo tamanho de valor não assinado seria suficiente.


4

Geralmente, é uma má idéia usar tipos não assinados, porque eles transbordam de maneiras desagradáveis. x = 5-6de repente é uma bomba de tempo no seu código. Enquanto isso, os benefícios de tipos não assinados se resumem a um único bit extra de precisão e, se esse bit vale a pena para você, você certamente deve usar um tipo maior.

Existem casos de uso em que um tipo menor pode fazer sentido, mas, a menos que você esteja preocupado com o uso da memória ou precise empacotar dados para obter eficiência de transmissão ou cache ou várias outras preocupações, geralmente não há benefício em usar um tipo menor . Além disso, em muitas arquiteturas, é realmente mais lento usar esses tipos para que eles possam impor um pequeno custo.


3
Em C, o estouro assinado é ainda pior que o não assinado (porque é um comportamento indefinido, enquanto não assinado é especificado para rolar como um odômetro). OTOH, over / underflow assinado é muito menos comum na prática do que underflow não assinado.
Kevin

É verdade, mas o estouro assinado geralmente é mais óbvio e previsível.
Jack Aidley

I geralmente concordam, mas você precisa estar ciente, por exemplo, que os compiladores modernos pode otimizar i+1>iem 1se ifor assinado, juntamente com toda uma série de outros comportamentos desagradável. Estouros não assinados podem causar um erro em uma caixa de canto. O excesso assinado pode tornar todo o seu programa sem sentido .
Kevin

@ JackAidley Tenho certeza de que o que você diz não faz sentido, já que 5-6 produz o mesmo padrão de bits, não importa se está assinado ou não.
Ingo

@ Ingo: com que frequência você olha para padrões de bits? O que importa é o significado do padrão de bits e não os bits que estão ativados ou desativados.
Jack Aidley

2

Muitas vezes esquecido e possivelmente tangencial à sua pergunta, ao lidar especificamente com tipos .NET, é a conformidade com o CLS . Nem todos os tipos estão disponíveis para todos os idiomas criados no .NET Framework.

Se você está escrevendo um código para ser consumido por idiomas diferentes de C # e deseja que esse código seja garantido para interoperar com o maior número possível de idiomas .NET, você deve restringir o uso do tipo àqueles compatíveis com CLS.

Por exemplo, as versões anteriores do VB.NET (7.0 e 7.1) não suportavam números inteiros não assinados ( UInteger):

http://msdn.microsoft.com/en-us/library/aa903459(v=vs.71).aspx

Inteiros não assinados não são compatíveis com CLS e, portanto, devem ser usados ​​com cuidado se você não tiver certeza de quem será o consumidor da sua biblioteca de classes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.