web-dev-qa-db-fra.com

Utilisation de uint8, uint16 etc.

Actuellement, je travaille avec une base de code (C, C++ mixte) ciblée pour une plateforme MIPS 32 bits. Le processeur est assez moderne [pour mentionner que nous avons une bonne quantité de puissance de traitement et de mémoire].

La base de code utilise des types de données comme uint8 [entier non signé large de 1 octet], uint16 [entier non signé large de 2 octets], uint32 [entier non signé large de 4 octets] etc.

Je sais à quel point l'utilisation de ces constructions est utile lors du portage du code sur différentes plates-formes.

Mes questions sont:

  1. À quoi sert/avantage d'utiliser un uint16 où un uint32 suffira également (s'il y en a)?

  2. Y aura-t-il des économies dans l'utilisation de la mémoire en utilisant des types de données plus courts (compte tenu de l'alignement des données)?

  3. Si c'est pour économiser quelques octets de mémoire, est-ce quelque chose de sensé à faire dans du matériel moderne?

19
NeonGlow

À quoi sert/avantage d'utiliser un uint16 où un uint32 suffira également (s'il y en a)?

Si ces uint16s font partie de tableaux ou de structures, vous pouvez économiser de la mémoire et peut-être être en mesure de gérer des ensembles de données plus volumineux qu'avec uint32s dans ces mêmes tableaux ou structures. Cela dépend vraiment de votre code.

Les protocoles de données et les formats de fichiers peuvent utiliser uint16s et il peut ne pas être correct d'utiliser uint32s au lieu. Cela dépend du format et de la sémantique (par exemple, si vous avez besoin de valeurs pour passer de 65535 à 0, uint16 le fera automatiquement pendant que uint32 non).

OTOH, si ces uint16s ne sont que des variables locales ou globales uniques, les remplacer par des variables 32 bits peut ne pas faire de différence significative car elles sont susceptibles d'occuper le même espace en raison de l'alignement et elles sont transmises en tant que paramètres 32 bits (sur la pile ou dans les registres ) sur MIPS de toute façon.

Y aura-t-il des économies dans l'utilisation de la mémoire en utilisant des types de données plus courts (compte tenu de l'alignement des données)?

Il peut y avoir des économies, surtout lorsque uint16s font partie de nombreuses structures ou éléments de grands tableaux.

Si c'est pour économiser quelques octets de mémoire, est-ce quelque chose de sensé à faire dans du matériel moderne?

Oui, vous réduisez la bande passante mémoire (ce qui est toujours une bonne chose) et vous réduisez souvent divers échecs de cache (caches de données et TLB) lorsque vous utilisez moins de données.

23
Alexey Frunze

Tout d'abord, si vous avez défini des types tels que uint16, où sont-ils définis? Ce ne sont pas des types standard, ils seront donc définis dans un en-tête propriétaire - peut-être le vôtre ou peut être fourni par une bibliothèque tierce; dans ce cas, vous devez vous demander à quel point ce code est portable et si vous créez une dépendance qui pourrait ne pas avoir de sens dans une autre application.

Un autre problème est que de nombreuses bibliothèques (malencontreusement IMO) définissent de tels types avec divers noms tels que UINT16, uint16, U16 UI16, etc. Si de tels noms sont définis, ils devraient idéalement être placés dans un espace de noms ou avoir un préfixe spécifique à la bibliothèque pour indiquer avec quelle bibliothèque ils ont été définis pour être utilisés, par exemple rtos::uint16 à rtos_uint16.

Étant donné que la bibliothèque de normes ISO C99 fournit des types spécifiques de longueur de bits standard dans stdint.h, vous devriez préférer leur utilisation à celles définies dans un en-tête propriétaire ou tiers. Ces types ont un _t suffixe, par exemple uint16_t. En C++, ils peuvent être placés dans le std:: namespace (bien que ce ne soit pas une donnée puisque l'en-tête a été introduit en C99).

1] À quoi sert/avantage d'utiliser un uint16 où un uint32 suffira également (s'il y en a)?

Mis à part mes conseils précédents, préférez stdint.h's uint16_t, il existe au moins deux raisons légitimes d'utiliser des types spécifiques à la longueur:

  1. Pour correspondre à une largeur de registre matériel spécifique.
  2. Pour appliquer une API commune et compatible à travers différentes architectures.

2] Y aura-t-il des économies dans l'utilisation de la mémoire en utilisant des types de données plus courts (compte tenu de l'alignement des données)?

Peut-être, mais si la mémoire n'est pas votre problème, ce n'est pas une bonne raison de les utiliser. Il vaut peut-être la peine d'envisager des objets ou des tableaux de données volumineux, mais l'application à l'échelle mondiale en vaut rarement la peine.

3] Si c'est pour économiser quelques octets de mémoire, est-ce quelque chose de sensé à faire dans du matériel moderne?

Voir [2]. "matériel moderne" n'implique cependant pas nécessairement de grandes ressources; il y a beaucoup de 32 bits ARM Cortex-M avec seulement quelques Kb of RAM par exemple. C'est-à-dire plus sur l'espace, le coût et la consommation d'énergie que sur l'âge de la conception ou de l'architecture.

9
Clifford

cstdint contient des charges de typedefs à des fins différentes.

  • intN_t pour une largeur spécifique
  • int_fastN_t pour l'entier le plus rapide, qui a au moins N bits
  • int_leastN_t pour le plus petit entier, qui a au moins N bits
  • Leurs unsigned équivalents

Vous devez choisir en fonction de votre situation. Stocker des milliers dans un std::vector et ne fait pas beaucoup de calculs? intN_t est probablement votre homme. Besoin d'un calcul rapide sur un petit nombre d'entiers? int_fastN_t est probablement votre gars.

4
Alex Chamberlain

Il faut vérifier le code machine/assembleur produit pour vérifier qu'il y a une sauvegarde de code. Dans les architectures de type RISC, l'immédiat typique est de 16 bits, mais l'utilisation de uint16_t consommera de toute façon un registre complet de 32 bits - donc, si vous utilisez des types int, mais s'engager à utiliser des valeurs proches de zéro produira les mêmes résultats et sera plus portable.

La sauvegarde de la mémoire de l'OMI vaut également sur les plates-formes modernes. Un code plus strict conduit par exemple à meilleure autonomie de la batterie et UX plus fluide. Cependant, je suggérerais de micro-gérer la taille uniquement lorsque vous travaillez avec des (grandes) baies, ou lorsque la variable correspond à une ressource matérielle réelle.

ps. Les compilateurs sont intelligents, mais les gens qui les écrivent travaillent pour le moment, ce qui les rend encore meilleurs.

2
Aki Suihkonen

Rép. 1. Le logiciel a certaines exigences et spécifications qui indiquent strictement de ne prendre que 8/16 bits d'un paramètre lors du codage/décodage ou d'une autre utilisation certaine. Donc, même si u attribue une valeur supérieure à 127 dans un disons u8, il coupe automatiquement les données pour vous.

Rép. 2. Nous ne devons pas oublier que nos compilateurs sont bien au-delà de l'intelligence pour faire l'optimisation, que ce soit la mémoire ou la complexité. Il est donc toujours recommandé d'utiliser une mémoire plus petite lorsque cela est possible.

Rép. 3. Bien sûr, économiser de la mémoire est logique sur les appareils modernes.

2
paper.plane

Utilisation de types entiers de largeur exacte comme int32_t et amis est utile pour éviter les bogues d'extension de signe entre les plates-formes qui ont des tailles différentes pour int et long. Cela peut se produire lors de l'application de masques de bits ou lors du décalage de bits, par exemple. Si vous effectuez ces opérations sur un long par exemple, et que votre code fonctionne pour un long 32 bits, il peut se casser pour un long 64 bits. Si par contre vous utilisez un uint32_t, vous savez exactement quels résultats vous obtiendrez quelle que soit la plateforme.

Ils sont également utiles pour échanger des données binaires entre plates-formes, où vous n'avez qu'à vous soucier de l'endianité des données stockées et non de la largeur de bit; si vous écrivez un int64_t dans un fichier, vous savez que sur une autre plate-forme, vous pouvez le lire et le stocker dans un int64_t. Si vous écriviez un long au lieu de 64 bits sur une seule plate-forme, vous pourriez avoir besoin d'un long long sur une autre plate-forme car long il n'y a que 32 bits.

Sauver la mémoire n'est généralement pas la raison, sauf si vous parlez d'environnements très limités (trucs intégrés) ou de grands ensembles de données (comme un tableau avec 50 millions d'éléments ou autres).

1
Nikos C.

En utilisant uint16_t au lieu de uint32_t économise de la mémoire. Cela peut également être une contrainte matérielle (par exemple, un contrôleur périphérique envoie vraiment 16 bits!) Cependant, cela peut ne pas valoir la peine de l'utiliser, en raison de considérations de cache et d'alignement (vous devez vraiment comparer).

1
Basile Starynkevitch

À quoi sert/avantage d'utiliser un uint16 où un uint32 suffira également (s'il y en a)?

Il existe des CPU où unsigned char est une valeur de 16 bits. Le test unitaire de ce code serait difficile sans l'utilisation de typedefs (uint16 n'est qu'un typedef pour le type approprié).

De plus, avec l'utilisation de ces typedefs, il est plus facile de construire sur différentes plates-formes sans beaucoup de problèmes.

Y aura-t-il des économies dans l'utilisation de la mémoire en utilisant des types de données plus courts (compte tenu de l'alignement des données)?

Non, ce n'est pas un point. Si uint16 est un typedef pour unsigned short, vous pouvez alors utiliser unsigned short partout, mais vous pouvez obtenir différents types sur différentes plates-formes.

Bien sûr, l'utilisation d'un type plus petit réduira la consommation de mémoire. Par exemple, en utilisant uint16 au lieu de uint32, mais uniquement si vous utilisez des tableaux.

Si c'est pour économiser quelques octets de mémoire, est-ce quelque chose de sensé à faire dans du matériel moderne?

Cela dépend de la plateforme:

  • moins d'utilisation de la mémoire signifie moins de ratés de cache
  • si pris en charge, il existe des fonctions SIMD qui traitent les données 16 bits
1
BЈовић

Les réponses à vos questions se résument à un concept clé: quelle est la taille des données? Si vous en consommez beaucoup, l'avantage d'utiliser des types de données plus petits est évident. Pensez-y de cette façon: le simple calcul du plus grand nombre premier connu récemment découvert pourrait vous faire manquer de mémoire sur un poste de travail typique. Le nombre lui-même prend plus d'un gigaoctet juste pour le stocker. Cela n'inclut pas le calcul du nombre réel. Si vous deviez utiliser un type de données épais au lieu d'un type mince, vous envisagez peut-être deux gigaoctets à la place. Un exemple simpliste, mais néanmoins bon.

1
L0j1k