Dans l'ISO / CEI 9899: 2018 (C18), il est indiqué sous 7.20.1.3:
7.20.1.3 Types entiers de largeur minimale les plus rapides
1 Chacun des types suivants désigne un type entier qui est généralement le plus rapide 268) pour fonctionner avec tous les types entiers qui ont au moins la largeur spécifiée.
2 Le nom typedef
int_fastN_t
désigne le type entier signé le plus rapide avec une largeur d'au moins N. Le nom typedefuint_fastN_t
désigne le type entier non signé le plus rapide avec une largeur d'au moins N.3 Les types suivants sont requis:
int_fast8_t
,int_fast16_t
,int_fast32_t
,int_fast64_t
,uint_fast8_t
,uint_fast16_t
,uint_fast32_t
,uint_fast64_t
Tous les autres types de ce formulaire sont facultatifs.
268) Le type désigné n'est pas garanti d'être le plus rapide à toutes fins; si la mise en œuvre n'a pas de raisons claires de choisir un type plutôt qu'un autre, elle choisira simplement un type entier satisfaisant aux exigences de signature et de largeur.
Mais il n'est pas précisé pourquoi ces types entiers "rapides" sont plus rapides.
- Pourquoi ces types entiers rapides sont-ils plus rapides que les autres types entiers?
J'ai marqué la question avec C ++, car les types d'entiers rapides sont également disponibles en C ++ 17 dans le fichier d'en-tête de cstdint
. Malheureusement, dans l'ISO / CEI 14882: 2017 (C ++ 17), aucune explication de ce type n'existe; J'avais mis en œuvre cette section autrement dans le corps de la question.
Information: en C, ils sont déclarés dans le fichier d'en-tête de stdint.h
.
typedef
déclarations. Donc, généralement , cela se fait au niveau de la bibliothèque standard. Bien sûr, les C standards ne met aucune restriction réelle sur ce qu'ilstypedef
à - ainsi , par exemple une mise en œuvre typique est de faireint_fast32_t
untypedef
deint
sur un système 32 bits, mais un compilateur hypothétique pourrait par exemple mettre en œuvre un__int_fast
type intrinsèque et promettent de faire un peu de fantaisie optimisations pour choisir le type de machine le plus rapide au cas par cas pour les variables de ce type, et la bibliothèque pourrait alors letypedef
faire.Réponses:
Imaginez un processeur qui effectue uniquement des opérations arithmétiques 64 bits. Imaginez maintenant comment vous implémenteriez un ajout 8 bits non signé sur un tel processeur. Il faudrait nécessairement plus d'une opération pour obtenir le bon résultat. Sur un tel processeur, les opérations 64 bits sont plus rapides que les opérations sur d'autres largeurs entières. Dans cette situation, tous
Xint_fastY_t
pourraient vraisemblablement être un alias de type 64 bits.Si un processeur prend en charge les opérations rapides pour les types entiers étroits et qu'un type plus large n'est donc pas plus rapide qu'un type plus étroit, il
Xint_fastY_t
ne s'agira pas d'un alias du type plus large que nécessaire pour représenter tous les Y bits.Par curiosité, j'ai vérifié les tailles d'une implémentation particulière (GNU, Linux) sur certaines architectures. Ce ne sont pas les mêmes pour toutes les implémentations sur la même architecture:
Notez que bien que les opérations sur les types plus grands puissent être plus rapides, ces types prennent également plus d'espace dans le cache, et donc leur utilisation ne donne pas nécessairement de meilleures performances. En outre, on ne peut pas toujours croire que la mise en œuvre a fait le bon choix en premier lieu. Comme toujours, la mesure est requise pour des résultats optimaux.
Capture d'écran du tableau, pour les utilisateurs d'Android:
(Android n'a pas de caractères de dessin de boîte dans la police mono - ref )
la source
Ils ne le sont pas, du moins pas de manière fiable.
Les types rapides sont simplement des typedefs pour les types réguliers, mais c'est à l'implémentation comment les définir. Ils doivent être au moins de la taille demandée, mais ils peuvent être plus grands.
Il est vrai que sur certaines architectures certains types entiers ont de meilleures performances que d'autres. Par exemple, les premières implémentations ARM avaient des instructions d'accès à la mémoire pour les mots 32 bits et pour les octets non signés, mais elles n'avaient pas d'instructions pour les demi-mots ou les octets signés. Les instructions d'un demi-mot et d'octets signés ont été ajoutées plus tard, mais elles ont toujours des options d'adressage moins flexibles, car elles devaient être placées dans l'espace de codage de rechange. De plus, toutes les instructions de traitement des données réelles sur ARM fonctionnent sur les mots, donc dans certains cas, il peut être nécessaire de masquer les valeurs plus petites après le calcul pour donner des résultats corrects.
Cependant, il y a aussi la préoccupation concurrente de la pression du cache, même s'il faut plus d'instructions pour charger / stocker / traiter une valeur plus petite. La valeur plus petite peut tout de même fonctionner mieux si elle réduit le nombre de ratés de cache.
Les définitions des types sur de nombreuses plates-formes communes ne semblent pas avoir été réfléchies. En particulier, les plates-formes 64 bits modernes tendent à avoir une bonne prise en charge des entiers 32 bits, mais les types "rapides" sont souvent inutilement 64 bits sur ces plates-formes.
De plus, les types en C font partie de l'ABI de la plateforme. Ainsi, même si un fournisseur de plate-forme découvre qu'il a fait des choix stupides, il est difficile de modifier ces choix stupides plus tard.
Ignorez les types "rapides". Si vous êtes vraiment préoccupé par les performances entières, comparez votre code avec toutes les tailles disponibles.
la source
Les types rapides ne sont pas plus rapides que tous les autres types entiers - ils sont en fait identiques à certains types entiers "normaux" (ils ne sont qu'un alias pour ce type) - quel que soit le type qui s'avère le plus rapide pour conserver une valeur de au moins autant de bits.
Il dépend simplement de la plate-forme pour quel type entier chaque type rapide est un alias.
la source