Quali sono i casi in cui i tipi di dati 'uint' e 'short' si adattano meglio allo standard int (32)?


24

Comprendo le differenze di capacità e valori che possono rappresentare, ma sembra che le persone usino sempreInt32 indipendentemente dal fatto che sia appropriato. Nessuno sembra mai usare la versione senza segno ( uint) anche se molto spesso si adatta meglio in quanto descrive un valore che non può essere negativo (forse per rappresentare un ID di un record di database). Inoltre, nessuno sembra mai utilizzare short/Int16indipendentemente dalla capacità richiesta del valore.

Oggettivamente, ci sono casi in cui è meglio usare uinto short/Int16e se sì, quali sono?


13
La popolarità non è sempre una metrica praticabile per valutare le decisioni di progettazione del software. Solo perché una pratica è popolare non significa che sia una pratica appropriata per la tua particolare applicazione o che sia anche una buona pratica.
Robert Harvey,


1
La risposta breve, penso, è che i programmatori si sono abituati alla semantica firmata e sono propensi ad assumerla, anche quando hanno a che fare con tipi non firmati (e quindi semantica non firmata). La maggior parte delle persone presume che il programmatore sia pigro o non istruito, ma il programmatore in questione può in effetti essere molto istruito e molto attento e vuole evitare insidie ​​sottili. Se ti piace, dai un'occhiata a soundsoftware.ac.uk/c-pitfall-unsigned e anteru.net/2010/05/17/736 .
Theodoros Chatzigiannakis,

In un numero senza segno, il segno è più nullche positivo o negativo. Se lo consideri come qualcosa che non può mai essere negativo o sempre positivo, rimarrai sorpreso (e spesso arrabbiato) dai risultati perché non funziona in questo modo, soprattutto se confrontato con o sottratto a / dai valori firmati.
Adam D. Ruppe,

1
Nella mia esperienza, molti programmatori, che hanno mai programmato in linguaggio C, tendono a preoccuparsi dei byte, ancora in questi giorni, di GB di memoria e spazio di archiviazione.
user1451111

Risposte:


25

Sospetto che ti riferisca a una prospettiva colorata dalle tue stesse esperienze in cui non hai lavorato con persone che usano correttamente i tipi integrali. Questo potrebbe essere un evento comune, ma è stata la mia esperienza che le persone comunemente li usano anche correttamente.

Il vantaggio è lo spazio di memoria e il tempo della CPU, eventualmente anche lo spazio IO, a seconda che i tipi vengano mai inviati via cavo o su un disco. I tipi senza segno offrono controlli del compilatore per assicurarsi che non vengano eseguite determinate operazioni impossibili, oltre a estendere l'intervallo disponibile mantenendo le dimensioni più ridotte per prestazioni più elevate laddove necessario.

L' uso corretto è come ti aspetteresti: ogni volta che sai per certo puoi usarli in modo permanente (non vincolarli senza certezza o te ne pentirai in seguito).

  • Se stai cercando di rappresentare qualcosa che non potrebbe mai essere ragionevolmente negativo ( public uint NumberOfPeople) usa un tipo senza segno.
  • Se stai cercando di rappresentare qualcosa che non potrebbe mai ragionevolmente essere maggiore di 255 ( public byte DamagedToothCount), usa un byte.
  • Se stai cercando di rappresentare qualcosa che potrebbe ragionevolmente essere maggiore di 255, ma mai un numero significativo di migliaia , usa un short ( public short JimmyHoffasBankBalance).
  • Se stai cercando di rappresentare qualcosa che potrebbe essere molte centinaia di migliaia, milioni anche, ma che probabilmente non raggiungerà mai più miliardi, usa un int ( public int HoursSinceUnixEpoch).
  • Se sai per certo che questo numero può avere un valore illimitato o pensi che possa avere più miliardi ma non sei sicuro di quanti miliardi, la scommessa migliore è lunga. Se il tempo non è abbastanza grande, hai un problema interessante e devi iniziare a guardare numeri arbitrari di precisione ( public long MyReallyGreatAppsUserCountThisIsNotWishfulThinkingAtAll).

Questo ragionamento può essere utilizzato in tutto nella scelta tra tipi firmati, non firmati e varie dimensioni di tipi e altri, basti pensare alle verità logiche dei dati che stai rappresentando nella realtà.


11
+1, anche se devo chiarire che i "numeri" del telefono non sono numeri ma stringhe di cifre e, facoltativamente, formattazione. Sembra che tu ne sia consapevole, ma non vogliamo dare il cattivo esempio, ora lo facciamo? Inoltre, limitare arbitrariamente l'intervallo di un certo valore è un antipattern miope - intovunque a meno che tu non sappia per certo che il dominio problematico in realtà limita il valore - nessuna banca vorrebbe limitare i conti a 33.000 sterline (e pensare al divertimento quando trabocca ...!).
amon,

3
Nuovo obiettivo di vita: bozza eccessiva considerevole che sottostà al tipo integrale del mio conto bancario.
recursion.ninja,

11
Vi sono buoni motivi per non utilizzare tipi senza segno in determinati luoghi, ad esempio quando l'aritmetica viene mescolata tra firmato e non firmato. Vedi Quali sono le migliori pratiche relative agli ints non firmati? .

19
Non sono d'accordo con il ragionamento qui. I tipi senza segno sono spesso un errore a causa della sottrazione e dei confronti sono inattesi se si è abituati agli ints (funzionano in modo coerente ma non sono "sempre positivi"). Li eviterei a meno che tu non abbia un motivo molto specifico per usarli. Inoltre, perché le dimensioni contano per byte vs short vs int? Spesso non si risparmia nemmeno spazio, poiché le strutture riempiono quei membri o array con un certo allineamento. Vorrei usare un byte solo se la dimensione è davvero importante (improbabile soprattutto per il codice C # che ho visto) o se si desidera specificamente wraparound a 255 per qualcosa.
Adam D. Ruppe,

4
"Il vantaggio è lo spazio di memoria e il tempo della CPU" ... Non vedo alcun caso in cui i tipi minuscoli risparmierebbero effettivamente il tempo della CPU. Le operazioni intere non diventano mai più veloci di quelle dei tipi di dimensioni macchina , vale a dire per quanto riguarda la CPU che potresti usare long. Il risparmio di memoria può ovviamente indirettamente risparmiare tempo migliorando l'efficienza della cache-line e così via, ma OTOH i problemi di allineamento con tipi piccoli possono indirettamente costare tempo.
lasciato il

16

Certo, ci sono casi in cui è meglio usare uinto shorto Int16. Quando sai che il tuo intervallo di dati si adatta ai vincoli di quel tipo di variabile, allora va bene usare quel tipo.

In ambienti con problemi di memoria o quando si ha a che fare con grandi quantità di oggetti, può avere senso usare la variabile di dimensione più piccola. Ad esempio, esiste una differenza significativa nelle dimensioni per un array di milioni di elementi di ints vs. shorts.

Spesso, ciò non accade nel codice effettivo per uno o più dei seguenti motivi:

  • I vincoli dei dati non erano noti in anticipo
  • C'era la possibilità che i vincoli dei dati non fossero solidi o che si sapesse probabilmente cambiati
  • Si sperava di riutilizzare la funzione con un intervallo di dati più ampio
  • Lo sviluppatore non ha impiegato del tempo per riflettere sui vincoli
  • Il risparmio di memoria era insignificante da giustificare l'utilizzo di un tipo di variabile più piccolo

Ci sono molte più ragioni possibili, ma si riducono a questo: il tempo impiegato per decidere e utilizzare un diverso tipo di variabile non ha fornito vantaggi sufficienti per giustificare farlo.


8

In C, in contesti che non prevedono la promozione di numeri interi , sono stati specificati valori non firmati per comportarsi come membri di un anello algebrico astratto "avvolgente" (quindi per ogni X e Y, XY produrrà un valore univoco che, se aggiunto a Y, produrrà X ), mentre i tipi di numeri interi con segno sono stati specificati come comportati come numeri interi quando i calcoli sono rimasti entro un certo intervallo e hanno permesso di fare qualsiasi cosa quando i calcoli sono andati oltre. La semantica numerica in C #, tuttavia, è totalmente diversa. Quando si trovano in un contesto numerico controllato, sia i tipi con segno che quelli senza segno si comportano come numeri interi purché i calcoli rimangano nel range e si lancino OverflowExceptionquando non lo fanno; in un contesto non controllato, entrambi si comportano come anelli algebrici.

L'unica volta in cui vale la pena usare qualsiasi tipo di dati di dimensioni inferiori rispetto a Int32quando è necessario impacchettare o disimballare le cose per immagazzinaggio o trasporto compatto. Se uno ha bisogno di memorizzare mezzo miliardo di numeri positivi e saranno tutti nell'intervallo da 0 a 100, usando un byte ciascuno anziché quattro risparmierà 1,5 gigabyte di spazio di archiviazione. Questo è un grande risparmio. Se un pezzo di codice deve memorizzare un totale di circa duecento valori, tuttavia, rendendo ciascuno di essi un byte anziché quattro, si risparmierebbero circa 600 byte. Probabilmente non vale la pena preoccuparsene.

Per quanto riguarda i tipi senza segno, le uniche volte in cui sono veramente utili sono quando si esegue lo scambio di informazioni o quando si suddividono i numeri in pezzi. Se, ad esempio, è necessario eseguire la matematica su numeri interi a 96 bit, sarà probabilmente molto più semplice eseguire i calcoli su gruppi di tre numeri interi a 32 bit senza segno, piuttosto che su gruppi di numeri interi con segno. Altrimenti, non ci sono molte situazioni in cui l'intervallo di un valore con segno a 32 o 64 bit sarebbe inadeguato, ma le stesse dimensioni del valore senza segno sarebbero sufficienti.


4

È generalmente una cattiva idea usare tipi non firmati perché traboccano in modi spiacevoli. x = 5-6è improvvisamente una bomba a orologeria nel tuo codice. Nel frattempo, i vantaggi dei tipi senza segno si riducono a un singolo tocco in più di precisione, e se quel bit ne vale la pena, dovresti quasi sicuramente utilizzare un tipo più grande.

Ci sono casi d'uso in cui un tipo più piccolo potrebbe avere senso, ma a meno che tu non sia preoccupato per l'utilizzo della memoria o abbia bisogno di comprimere i dati per la trasmissione o l'efficienza della cache o una manciata di altre preoccupazioni, di solito è il caso che non ci sia alcun vantaggio nell'utilizzare un tipo più piccolo . Inoltre, su molte architetture, è effettivamente più lento utilizzare questi tipi in modo che possano effettivamente imporre un piccolo costo.


3
In C, l'overflow con segno è persino peggiore dell'overflow senza segno (perché è un comportamento indefinito, mentre il segno senza segno è specificato per il rotolamento come un contachilometri). OTOH, firmato overflow / underflow è molto meno comune nella pratica rispetto al underflow non firmato.
Kevin,

Vero, ma l'overflow firmato è in genere più ovvio e prevedibile.
Jack Aidley,

Io generalmente d'accordo, ma si ha bisogno di essere a conoscenza, per esempio, che i compilatori moderni possono ottimizzare i+1>iin 1se iè firmato, insieme a tutta una serie di altri comportamenti cattivi. Un overflow senza segno può causare un bug in un caso angolare. L'overflow firmato può rendere insignificante l'intero programma .
Kevin,

@JackAidley Sono abbastanza sicuro che quello che dici non abbia senso, dato che 5-6 produce lo stesso schema di bit, indipendentemente dal fatto che sia senza segno o meno.
Ingo,

@Ingo: quanto spesso guardi gli schemi di bit? Ciò che conta è il significato del modello di bit, non i bit che sono attivi o meno.
Jack Aidley il

2

Spesso la conformità CLS è spesso dimenticata e forse tangente alla tua domanda, quando si tratta specificamente di tipi .NET . Non tutti i tipi sono disponibili per tutte le lingue basate su .NET Framework.

Se stai scrivendo codice che verrà utilizzato da lingue diverse da C # e desideri che quel codice sia garantito per interagire con il maggior numero possibile di lingue .NET, devi limitare l'utilizzo del tipo a quelli compatibili con CLS.

Ad esempio, le prime versioni di VB.NET (7.0 e 7.1) non supportavano numeri interi senza segno ( UInteger):

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

I numeri interi senza segno non sono conformi a CLS e pertanto devono essere utilizzati con attenzione se non si è sicuri di chi sarà il consumatore della libreria di classi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.