Dans quels cas les types de données 'uint' et 'short' sont-ils mieux adaptés que le standard int (32)?


24

Je comprends les différences de capacité et de valeurs qu'ils peuvent représenter, mais il semble que les gens utilisent toujours,Int32 que ce soit approprié ou non. Personne ne semble jamais utiliser la version non signée ( uint) même si la plupart du temps elle convient mieux car elle décrit une valeur qui ne peut pas être négative (peut-être pour représenter l'ID d'un enregistrement de base de données). De plus, personne ne semble jamais utiliser short/Int16quelle que soit la capacité requise de la valeur.

Objectivement, y a-t-il des cas où il est préférable d'utiliser uintou short/Int16si oui, quels sont-ils?


13
La popularité n'est pas toujours une mesure viable pour évaluer les décisions de conception de logiciels. Ce n'est pas parce qu'une pratique est populaire que c'est une pratique appropriée pour votre application particulière, ou même une bonne pratique.
Robert Harvey


1
La réponse courte, je pense, est que les programmeurs se sont habitués à la sémantique signée et sont enclins à l'assumer, même lorsqu'ils traitent de types non signés (et donc de sémantique non signée). La plupart des gens supposent qu'il s'agit d'un programmeur paresseux ou sans instruction, mais le programmeur en question peut en fait être très éduqué et très prudent et veut éviter les pièges subtils. Si vous le souhaitez, jetez un œil à sonsoftware.ac.uk/c-pitfall-unsigned et anteru.net/2010/05/17/736 .
Theodoros Chatzigiannakis du

Dans un nombre non signé, le signe est plus nullque positif ou négatif. Si vous le considérez comme quelque chose qui ne peut jamais être négatif ou est toujours positif, vous allez être surpris (et souvent en colère) des résultats parce que cela ne fonctionne pas vraiment de cette façon, surtout en comparaison avec ou soustrait à / à partir de valeurs signées.
Adam D. Ruppe

1
D'après mon expérience, beaucoup de programmeurs, qui ont déjà programmé en langage C, ont tendance à se soucier des octets, toujours de nos jours, de Go de mémoire et d'espace de stockage.
user1451111

Réponses:


25

Je suppose que vous faites référence à une perspective colorée par vos propres expériences où vous n'avez pas travaillé avec des gens qui utilisent correctement les types intégraux. Cela peut bien être un phénomène courant, mais d'après mon expérience, les gens les utilisent également correctement.

L'avantage est l'espace mémoire et le temps processeur, éventuellement l'espace IO également selon que les types sont envoyés sur le câble ou sur un disque. Les types non signés vous donnent des vérifications du compilateur pour vous assurer que vous ne ferez pas certaines opérations qui sont impossibles, en plus d'étendre la plage disponible tout en conservant la plus petite taille pour des performances accrues là où cela peut être nécessaire.

L' utilisation correcte est celle que vous attendez - chaque fois que vous en êtes certain, vous pouvez les utiliser de manière permanente (ne contraignez pas sans certitude ou vous le regretterez plus tard).

  • Si vous essayez de représenter quelque chose qui ne pourrait jamais être raisonnablement négatif ( public uint NumberOfPeople), utilisez un type non signé.
  • Si vous essayez de représenter quelque chose qui ne pourrait jamais être raisonnablement supérieur à 255 ( public byte DamagedToothCount), utilisez un octet.
  • Si vous essayez de représenter quelque chose qui pourrait raisonnablement être supérieur à 255, mais jamais un nombre significatif de milliers , utilisez un short ( public short JimmyHoffasBankBalance).
  • Si vous essayez de représenter quelque chose qui pourrait atteindre plusieurs centaines de milliers, voire plusieurs millions, mais qui ne devrait jamais atteindre plusieurs milliards, utilisez un int ( public int HoursSinceUnixEpoch).
  • Si vous savez avec certitude que ce nombre peut avoir une valeur illimitée ou si vous pensez qu'il peut avoir plusieurs milliards, mais vous n'êtes pas certain du nombre de milliards, c'est longtemps votre meilleur pari. Si la longueur n'est pas assez grande, vous avez un problème intéressant et vous devez commencer à chercher des chiffres de précision arbitraires ( public long MyReallyGreatAppsUserCountThisIsNotWishfulThinkingAtAll).

Ce raisonnement peut être utilisé tout au long du choix entre les types de types signés, non signés et variés et autres, pensez simplement aux vérités logiques des données que vous représentez en réalité.


11
+1, même si je dois préciser que les «numéros» de téléphone ne sont pas des nombres mais des chaînes de chiffres et éventuellement une mise en forme. Vous semblez être au courant de cela, mais nous ne voulons pas donner le mauvais exemple, n'est-ce pas? En outre, restreindre arbitrairement la plage de certaines valeurs est un contre-modèle à courte vue - intpartout sauf si vous savez avec certitude que le domaine problématique limite réellement la valeur - aucune banque ne voudrait limiter les comptes à 33 000 livres sterling (et penser au plaisir quand ça déborde…!).
amon

3
Nouvel objectif de vie: sur-traite importante qui sous-tend le type intégral de mon compte bancaire.
recursion.ninja

11
Il existe de bonnes raisons de ne pas utiliser de types non signés à certains endroits, par exemple lorsque l'arithmétique est mélangée entre signé et non signé. Voir Quelles sont les meilleures pratiques concernant les entrées non signées? .

19
Je ne suis pas d'accord avec le raisonnement ici. Les types non signés sont souvent une erreur car la soustraction et les comparaisons sont inattendues si vous êtes habitué aux ints (ils fonctionnent de manière cohérente mais ce n'est pas "toujours positif"). Je les éviterais à moins d'avoir une raison très précise de les utiliser. Aussi, pourquoi la taille est-elle importante pour l'octet vs le short contre l'int? Souvent, vous n'économisez même pas d'espace, car les structures rempliront ces membres ou tableaux dans un certain alignement. Je n'utiliserais un octet que si la taille est vraiment importante (peu probable en particulier pour le code C # que j'ai vu) ou si vous voulez spécifiquement un enveloppement à 255 pour quelque chose.
Adam D. Ruppe du

4
"l'avantage est l'espace mémoire et le temps processeur" ... Je ne vois aucun cas où de minuscules types permettraient réellement d'économiser du temps CPU. Les opérations entières ne sont jamais plus rapides qu'elles ne le sont sur les types de la taille d'une machine , c'est-à-dire qu'en ce qui concerne le CPU, vous pourriez aussi bien l'utiliser long. L'économie de mémoire peut bien sûr indirectement gagner du temps en améliorant l'efficacité de la ligne de cache et ainsi de suite, mais OTOH les problèmes d'alignement avec les petits types peuvent indirectement coûter du temps.
gauche autour du

16

Bien sûr, il y a des cas où il vaut mieux utiliser uintou shortou Int16. Lorsque vous savez que votre plage de données s'adaptera aux contraintes de ce type de variable, vous pouvez utiliser ce type.

Dans les environnements à mémoire limitée ou lorsqu'il s'agit de grandes quantités d'objets, il peut être judicieux d'utiliser la plus petite variable de taille. Par exemple, il existe une différence de taille significative pour un tableau d'un million d'éléments de ints par rapport à shorts.

Souvent, cela ne se produit pas dans le code réel pour une ou plusieurs des raisons suivantes:

  • Les contraintes de données n'étaient pas connues à l'avance
  • Il y avait une chance que les contraintes de données n'étaient pas solides ou étaient susceptibles d'être modifiées
  • Il y avait un espoir de réutiliser la fonction avec une gamme de données plus large
  • Le développeur n'a pas pris le temps de réfléchir aux contraintes
  • Les économies de mémoire étaient insignifiantes pour justifier l'utilisation d'un type de variable plus petit

Il y a beaucoup plus de raisons possibles, mais elles se résument à ceci: le temps nécessaire pour décider et utiliser un type de variable différent n'a pas fourni suffisamment d'avantages pour le justifier.


8

En C, dans des contextes n'impliquant pas de promotion d'entiers , des valeurs non signées ont été spécifiées pour se comporter comme des membres d'un anneau algébrique abstrait "enveloppant" (donc pour tout X et Y, XY produira une valeur unique qui, une fois ajoutée à Y, produira X ), tandis que les types entiers signés étaient spécifiés comme se comportant comme des entiers lorsque les calculs restaient dans une certaine plage et autorisés à tout faire lorsque les calculs allaient au-delà. Cependant, la sémantique numérique en C # est totalement différente. Dans un contexte numérique vérifié, les types signés et non signés se comportent comme des entiers à condition que les calculs restent dans la plage et lancent OverflowExceptionquand ils ne le font pas; dans un contexte non contrôlé, ils se comportent tous les deux comme des anneaux algébriques.

La seule fois où cela vaut généralement la peine d'utiliser un type de données plus petit que Int32lorsqu'il est nécessaire d'emballer ou de déballer des objets pour un stockage ou un transport compact. Si l'on a besoin de stocker un demi-milliard de nombres positifs, et qu'ils seront tous compris entre 0 et 100, utiliser un octet chacun au lieu de quatre permettra d'économiser 1,5 gigaoctet de stockage. C'est une grosse économie. Si un morceau de code a besoin de stocker un total de quelques centaines de valeurs, cependant, faire de chacun d'eux un octet plutôt que quatre permettrait d'économiser environ 600 octets. Probablement pas la peine de s'en préoccuper.

En ce qui concerne les types non signés, les seuls moments où ils sont vraiment utiles sont lors de l'échange d'informations ou lors de la subdivision de nombres en morceaux. Si, par exemple, il faut faire des calculs sur des entiers 96 bits, il sera probablement beaucoup plus facile d'effectuer les calculs sur des groupes de trois entiers 32 bits non signés que sur des groupes d'entiers signés. Sinon, il n'y a pas beaucoup de situations où la plage d'une valeur signée 32 ou 64 bits serait inadéquate, mais la même taille de valeur non signée suffirait.


4

C'est généralement une mauvaise idée d'utiliser des types non signés car ils débordent de manière désagréable. x = 5-6est soudainement une bombe à retardement dans votre code. Pendant ce temps, les avantages des types non signés se résument à un seul bit supplémentaire de précision, et si ce bit en vaut la peine pour vous, vous devriez presque certainement utiliser un type plus grand à la place.

Il existe des cas d'utilisation où un type plus petit peut avoir un sens, mais à moins que vous ne soyez préoccupé par l'utilisation de la mémoire ou que vous ayez besoin de compresser les données pour la transmission ou l'efficacité du cache ou quelques autres préoccupations, il est généralement vrai qu'il n'y a aucun avantage à utiliser un type plus petit. . De plus, sur de nombreuses architectures, il est en fait plus lent d'utiliser ces types afin qu'ils puissent réellement imposer un faible coût.


3
En C, le débordement signé est encore pire que le débordement non signé (car c'est un comportement indéfini, tandis que non signé est spécifié pour rouler comme un odomètre). OTOH, les dépassements / dépassements signés sont beaucoup moins courants dans la pratique que les dépassements non signés.
Kevin

Vrai, mais le débordement signé est généralement plus évident et prévisible.
Jack Aidley

Je suis d' accord général, mais vous devez être au courant, par exemple, que les compilateurs modernes peuvent optimiser i+1>idans le 1cas iest signé, avec une foule d'autres comportements méchant. Un débordement non signé peut provoquer un bogue dans un cas d'angle. Un débordement signé peut rendre tout votre programme vide de sens .
Kevin

@JackAidley Je suis sûr que ce que vous dites n'a aucun sens, car 5-6 produit le même motif de bits, qu'il soit non signé ou non.
Ingo

@Ingo: à quelle fréquence examinez-vous les modèles de bits? Ce qui importe, c'est la signification de la configuration binaire et non les bits activés ou désactivés.
Jack Aidley

2

La conformité CLS est souvent oubliée et peut-être tangentielle à votre question, lorsqu'il s'agit spécifiquement de types .NET . Tous les types ne sont pas disponibles pour toutes les langues basées sur le .NET Framework.

Si vous écrivez du code destiné à être utilisé par des langages autres que C # et souhaitez que ce code soit garanti pour interagir avec autant de langages .NET que possible, vous devez restreindre votre utilisation de type à ceux qui sont conformes CLS.

Par exemple, les premières versions de VB.NET (7.0 et 7.1) ne prenaient pas en charge les entiers non signés ( UInteger):

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

Les entiers non signés ne sont pas conformes CLS et doivent donc être utilisés avec précaution si vous ne savez pas qui sera votre consommateur de bibliothèque de classe.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.