web-dev-qa-db-fra.com

Différence entre uint8_t, uint_fast8_t et uint_least8_t

La norme C99 introduit les types de données suivants. La documentation est disponible ici pour la bibliothèque AVR stdint.

  • uint8_t signifie que c'est un type non signé de 8 bits.
  • uint_fast8_t signifie que c'est le plus rapide des unsigned int avec au moins 8 bits.
  • uint_least8_t signifie que c'est un entier non signé avec au moins 8 bits.

Je comprends uint8_t et qu'est-ce que uint_fast8_t _ (Je ne sais pas comment cela est implémenté au niveau du registre).

1.Pouvez-vous expliquer quelle est la signification de "c’est un unsigned int avec au moins 8 bits "?

2.Comment uint_fast8_t et uint_least8_t aider à augmenter l'efficacité/l'espace de code par rapport au uint8_t?

69
mic

uint_least8_t Est le plus petit type comportant au moins 8 bits. uint_fast8_t Est le type le plus rapide comportant au moins 8 bits.

Vous pouvez voir les différences en imaginant des architectures exotiques. Imaginez une architecture 20 bits. Son unsigned int A 20 bits (un registre) et son unsigned char A 10 bits. Donc, sizeof(int) == 2, mais utiliser char types nécessite des instructions supplémentaires pour couper les registres de moitié. Ensuite:

  • uint8_t: N'est pas défini (pas de type 8 bits).
  • uint_least8_t: Est unsigned char, Le plus petit type d'au moins 8 bits.
  • uint_fast8_t: Est unsigned int, Car dans mon architecture imaginaire, une variable de demi-registre est plus lente que celle de registre complet.
83
rodrigo

La théorie va quelque chose comme:

uint8_t doit avoir exactement 8 bits, mais son existence n’est pas obligatoire. Vous devriez donc l'utiliser lorsque vous vous fiez au comportement * d'assignation modulo-256 d'un entier de 8 bits et où vous préféreriez un échec de compilation à un comportement incorrect sur des architectures obscures.

uint_least8_t doit être le plus petit type entier non signé disponible pouvant stocker au moins 8 bits. Vous l'utiliseriez lorsque vous souhaitez minimiser l'utilisation de la mémoire d'éléments tels que les grands tableaux.

uint_fast8_t est supposé être le type "le plus rapide" non signé pouvant stocker au moins 8 bits; Cependant, il n'est pas réellement garanti d'être le plus rapide pour une opération donnée sur un processeur donné. Vous l'utiliseriez dans le code de traitement qui effectue de nombreuses opérations sur la valeur.

La pratique est que les types "rapide" et "moins" ne sont pas beaucoup utilisés.

Les types "moins" ne sont vraiment utiles que si vous vous souciez de la portabilité pour obscurcir les architectures avec CHAR_BIT! = 8, ce que la plupart des gens ne font pas.

Le problème avec les types "rapides" est qu'il est difficile de cerner le "plus rapide". Un type plus petit peut signifier moins de charge sur le système de mémoire/cache, mais l'utilisation d'un type plus petit que le type natif peut nécessiter des instructions supplémentaires. En outre, le meilleur choix peut changer entre les versions d'architecture, mais les développeurs souhaitent souvent éviter de rompre ABI dans de tels cas.

En regardant certaines implémentations populaires, il semble que les définitions de uint_fastn_t soient assez arbitraires. La glibc semble les définir comme étant au moins la "taille de mot natif" du système en question, sans tenir compte du fait que de nombreux processeurs modernes (en particulier les processeurs 64 bits) prennent en charge spécifiquement les opérations rapides sur des éléments plus petits que leur mot natif. Taille. IOS les définit apparemment comme équivalents aux types à taille fixe. Les autres plates-formes peuvent varier.

Dans l’ensemble, si votre objectif est d’utiliser des codes serrés avec des nombres entiers minuscules, vous devez établir un point de repère votre code sur les plates-formes qui vous intéressent avec des types de tailles différentes pour voir ce qui fonctionne le mieux.

* Notez que, malheureusement, le comportement des affectations modulo-256 n'implique pas toujours l'arithmétique modulo-256, en raison du dysfonctionnement de la promotion de l'entier de C.

24
plugwash

uint8_t signifie: donnez-moi un entier non signé de 8 bits exactement.

uint_least8_t _ signifie: donnez-moi le plus petit type de unsigned int qui a au moins 8 bits. Optimiser pour la consommation de mémoire.

uint_fast8_t _ signifie: donnez-moi un entier non signé d'au moins 8 bits. Choisissez un type plus grand si cela rend mon programme plus rapide, pour des raisons d'alignement. Optimiser pour la vitesse.

De plus, contrairement aux types plain int, la version signée des types stdint.h ci-dessus est garantie au format complément à 2.

23
Lundin

Certains processeurs ne peuvent pas fonctionner aussi efficacement sur des types de données plus petits que sur des gros. Par exemple, étant donné:

uint32_t foo(uint32_t x, uint8_t y)
{
  x+=y;
  y+=2;
  x+=y;
  y+=4;
  x+=y;
  y+=6;
  x+=y;
  return x;
}

si y était uint32_t un compilateur pour le ARM Cortex-M3 pourrait simplement générer

add r0,r0,r1,asl #2   ; x+=(y<<2)
add r0,r0,#12         ; x+=12
bx  lr                ; return x

mais puisque y est uint8_t le compilateur devrait plutôt générer:

add r0,r0,r1          ; x+=y
add r1,r1,#2          ; Compute y+2
and r1,r1,#255        ; y=(y+2) & 255
add r0,r0,r1          ; x+=y
add r1,r1,#4          ; Compute y+4
and r1,r1,#255        ; y=(y+4) & 255
add r0,r0,r1          ; x+=y
add r1,r1,#6          ; Compute y+6
and r1,r1,#255        ; y=(y+6) & 255
add r0,r0,r1          ; x+=y
bx  lr                ; return x

Les types "rapides" avaient pour but de permettre aux compilateurs de remplacer les types plus petits qui ne pouvaient pas être traités efficacement par des types plus rapides. Malheureusement, la sémantique des types "rapides" est plutôt mal spécifiée, ce qui laisse à désirer des questions quant à savoir si les expressions seront évaluées à l'aide de mathématiques signées ou non signées.

5
supercat

1.Pouvez-vous expliquer quelle est la signification de "c'est un unsigned int avec au moins 8 bits"?

Cela devrait être évident. Cela signifie qu'il s'agit d'un type entier non signé et que sa largeur est d'au moins 8 bits. En réalité, cela signifie qu’il peut au moins contenir les nombres de 0 à 255, et qu’il ne peut certainement pas contenir de nombres négatifs, mais il peut également contenir des nombres supérieurs à 255.

Évidemment, vous ne devez utiliser aucun de ces types si vous prévoyez de stocker un nombre situé en dehors de la plage comprise entre 0 et 255 (et que vous voulez qu'il soit portable).

2.Comment uint_fast8_t et uint_least8_t aident-ils à augmenter l'efficacité/l'espace de code par rapport à uint8_t?

uint_fast8_t est nécessaire pour être plus rapide, vous devez donc l'utiliser si votre exigence est que le code soit rapide. uint_least8_t d'autre part, il faut qu'il n'y ait pas de candidat de taille inférieure - vous l'utiliserez donc si la taille vous préoccupe.


Et bien sûr, vous n'utilisez que uint8_t lorsque vous avez absolument besoin que ce soit exactement 8 bits. En utilisant uint8_t peut rendre le code non portable comme uint8_t ne doit pas nécessairement exister (car ce type de petit entier n'existe pas sur certaines plates-formes).

4
skyking

Les types d'entiers "rapides" sont définis comme étant les entiers les plus rapides disponibles avec au moins le nombre de bits requis (dans votre cas, 8).

Une plateforme peut définir uint_fast8_t comme uint8_t alors il n'y aura aucune différence de vitesse.

La raison en est qu'il existe des plates-formes qui sont plus lentes lorsqu'elles n'utilisent pas leur longueur de mot natif.

3
LPs