Je sais déjà que stdint
est utilisé lorsque vous avez besoin de tailles de variables spécifiques pour la portabilité entre plates-formes. Je n'ai pas vraiment un tel problème pour l'instant, mais quels sont les inconvénients et les avantages de l'utiliser en plus du fait déjà montré ci-dessus?
En cherchant cela sur stackoverflow et d'autres sites, j'ai trouvé 2 liens qui traitent du thème:
codealias.info - celui-ci parle de la portabilité du stdint.
stackoverflow - celui-ci est plus spécifique sur uint8_t .
Ces deux liens sont particulièrement utiles si l'on cherche à en savoir plus sur la raison principale de la portabilité de cet en-tête - . Mais pour moi, ce que j'aime le plus, c'est que je pense que uint8_t
Est plus propre que unsigned char
(Pour stocker une valeur de canal RBG par exemple), int32_t
Semble plus significatif que simplement int
, etc.
Donc, ma question est, quels sont exactement les inconvénients et les avantages de l'utilisation de stdint
en plus de la portabilité? Dois-je l'utiliser uniquement dans certaines parties spécifiques de mon code, ou partout? si partout, comment puis-je utiliser des fonctions comme atoi()
, strtok()
, etc. avec elle?
Merci!
L'utilisation de types bien définis rend le code beaucoup plus facile et plus sûr à porter, car vous n'aurez aucune surprise lorsque, par exemple, une machine interprète int
en 16 bits et une autre en 32 bits. Avec stdint.h, ce que vous tapez est ce que vous obtenez.
L'utilisation de int
etc rend également difficile la détection des promotions de type dangereux.
Un autre avantage est qu'en utilisant int8_t
au lieu de char
, vous savez que vous obtenez toujours une variable 8 bits signée. char
peut être signé ou non, c'est un comportement défini par l'implémentation et varie selon les compilateurs. Par conséquent, la valeur par défaut char
est très dangereuse à utiliser dans du code qui devrait être portable.
Si vous souhaitez indiquer au compilateur qu'une variable doit être optimisée, vous pouvez utiliser le uint_fastx_t
qui indique au compilateur d'utiliser le type entier le plus rapide possible, au moins aussi grand que 'x'. La plupart du temps, cela n'a pas d'importance, le compilateur est suffisamment intelligent pour effectuer des optimisations sur les tailles de type, peu importe ce que vous avez tapé. Entre les points de séquence, le compilateur peut implicitement changer le type en un autre que celui spécifié, tant qu'il n'affecte pas le résultat.
Aucun.
Référence: MISRA-C: 2004 règle 6.3. " les caractères typographiques qui indiquent la taille et la signature doivent être utilisés à la place des types de base".
EDIT: Suppression d'un exemple incorrect.
La seule raison d'utiliser uint8_t
Plutôt que unsigned char
(À part les préférences esthétiques) est si vous voulez documenter que votre programme nécessite que char
soit exactement 8 bits. uint8_t
Existe si et seulement si CHAR_BIT==8
, Selon les exigences de la norme C.
Les autres types intX_t
Et uintX_t
Sont utiles dans les situations suivantes:
&
).memcmp
ou à des fins de hachage).D'un autre côté, les types uint_least8_t
, Etc. sont utiles partout où vous voulez éviter d'utiliser des types inutiles ou lents mais devez vous assurer que vous pouvez stocker des valeurs d'une certaine ampleur. Par exemple, alors que long long
Est d'au moins 64 bits, il peut être de 128 bits sur certaines machines, et l'utiliser lorsque ce dont vous avez besoin est juste un type qui peut stocker des nombres 64 bits serait très coûteux sur ces machines . int_least64_t
Résout le problème.
J'éviterais d'utiliser les types [u]int_fastX_t
Entièrement car ils ont parfois changé sur une machine donnée (cassant l'ABI) et puisque les définitions sont généralement fausses. Par exemple, sur x86_64, le type entier 64 bits est considéré comme le type "rapide" pour les valeurs 16, 32 et 64 bits, mais tandis que l'addition, la soustraction et la multiplication ont exactement la même vitesse que vous utilisiez 32- bits ou 64 bits, la division est presque sûrement plus lente avec des types plus grands que nécessaire, et même s'ils étaient à la même vitesse, vous utilisez deux fois la mémoire sans aucun avantage.
Enfin, notez que les arguments que certaines réponses ont avancés concernant l'inefficacité de l'utilisation de int32_t
Pour un compteur quand ce n'est pas la taille entière native sont techniquement généralement corrects, mais il n'est pas pertinent de corriger le code. À moins que vous ne comptiez un petit nombre de choses où le nombre maximal est sous votre contrôle, ou quelque chose externe (pas dans la mémoire de votre programme) où le nombre pourrait être astronomique, le type correct pour un nombre est presque toujours size_t
. C'est pourquoi toutes les fonctions C standard utilisent size_t
Pour les décomptes. N'envisagez pas d'utiliser autre chose à moins d'avoir une très bonne raison.
La principale raison pour laquelle le langage C ne spécifie pas la taille de int
ou long
, etc. est pour l'efficacité du calcul. Chaque architecture a une taille naturelle et la plus efficace, et les concepteurs ont spécifiquement habilité et prévu l'implémentateur du compilateur à utiliser les données de taille de données natives naturelles pour la vitesse et l'efficacité de la taille du code.
Au cours des années passées, la communication avec d'autres machines n'était pas une préoccupation principale - la plupart des programmes étaient locaux sur la machine - donc la prévisibilité de la taille de chaque type de données était peu préoccupante.
Insister pour qu'une architecture particulière utilise une taille particulière int
pour compter est vraiment mauvaise idée, même si cela semble rendre les choses plus faciles.
D'une certaine manière, grâce à XML et à ses frères, la taille du type de données n'est plus une préoccupation majeure. L'expédition de structures binaires spécifiques à une machine d'une machine à l'autre est encore une fois l'exception plutôt que la règle.
J'utilise les types stdint pour une seule raison, lorsque les données que je garde en mémoire doivent aller sur disque/réseau/descripteur sous forme binaire. Vous n'avez qu'à lutter contre le problème du petit endian/big-endian mais c'est relativement facile à surmonter .
La raison évidente de ne pas utiliser stdint est que le code est indépendant de la taille, en termes mathématiques tout ce qui fonctionne sur les entiers rationnels. Cela produirait des doublons de code moches si vous fournissiez une version uint*_t
De, disons, qsort()
pour chaque expansion de *
.
J'utilise mes propres types dans ce cas, dérivés de size_t
Lorsque je suis paresseux ou du plus grand entier non signé pris en charge sur la plate-forme lorsque je ne le suis pas.
Modifier, car j'ai rencontré ce problème plus tôt:
Je pense qu'il est à noter qu'au moins uint8_t
, uint32_t
Et uint64_t
Sont rompus dans Solaris 2.5.1. Donc, pour une portabilité maximale, je suggère toujours d'éviter stdint.h
(Au moins pour les prochaines années).