Comment vérifier si des entiers à largeur fixe sont définis

25

En C ++, les entiers à largeur fixe sont définis comme facultatifs , mais je n'arrive pas à trouver la méthode recommandée pour vérifier s'ils sont réellement définis.

Quelle serait une façon portable de vérifier si des entiers à largeur fixe sont disponibles?

Rick de Water
la source
Il ne semble pas y avoir de macro de test de fonctionnalités , mais je suppose que vous pouvez le faire#if defined(INT8_MIN)
Zereges
2
Si la bibliothèque std ne fournit pas de macro de test de fonctionnalité pour cela, vous pouvez vérifier si la chaîne d'outils que vous utilisez en fournit une ou vous permet de définir un propre test. CMake, par exemple, vous permet de tester certaines fonctionnalités du langage en compilant un cppfichier défini et selon que la compilation échoue ou non, une macro que vous pouvez définir est définie.
t.niese
Si vous préférez autoconf à cmake, il a des tests prédéfinis pour eux. AC_TYPE_INT8_Tetc.
Shawn
Si quelqu'un a un score de balise dans stdint , l'OMI cstdint doit être désigné comme synonyme ( stackoverflow.com/tags/stdint/synonymes ). Je ne pense pas que nous ayons besoin de balises C et C ++ séparées pour cette chose obscure; la balise principale sur la question suffit.
Peter Cordes
1
@PeterCordes Cela a fonctionné cette fois: stackoverflow.com/tags/stdint/synonymes
Andrew Henle

Réponses:

16

Pour déterminer si un type entier à largeur fixe est fourni, vous pouvez vérifier si l'une des macros correspondantes [U]INT*_MAXou [U]INT*_MINest définie.

// may be necessary for your C++ implementation
#define __STDC_LIMIT_MACROS 
#include <cstdint>

#ifdef INT32_MAX
// int32_t must be available to get here
int32_t some32bitIntVariable;
#endif

Par 7.20 types entiers<stdint.h> , paragraphe 4 de la norme C11 (notez les parties en gras):

Pour chaque type décrit ici que l'implémentation fournit, <stdint.h>doit déclarer ce typedefnom et définir les macros associées . Inversement, pour chaque type décrit ici que l'implémentation ne fournit pas, <stdint.h>ne doit pas déclarer ce typedefnom ni définir les macros associées .

C ++ hérite de l'implémentation C via <cstdint>. Voir <cstdint>vs<stdint.h> pour quelques détails. Voir aussi Que font __STDC_LIMIT_MACROSet __STDC_CONSTANT_MACROSsignifient? pour plus de détails __STDC_LIMIT_MACROS.

Ainsi, si int32_test disponible INT32_MAXet INT32_MINdoit être #define'd. Inversement, s'il int32_tn'est pas disponible, ni INT32_MAXne INT32_MINpeut l'être #define.

Notez cependant, comme @NicolBolas l'a indiqué dans une autre réponse , il n'est peut-être pas nécessaire de vérifier réellement.

Andrew Henle
la source
Il sera plus court de vérifier la [U]INT*_Cplace des macros min et max
phuclv
1
@phuclv Sauf que ce n'est pas la même chose. par exemple INT64_Cest défini si int64_least_test disponible, pas si int64_test disponible. Reportez-vous à la documentation
Courses de légèreté en orbite le
19

D'une manière générale ... vous ne le faites pas.

Si vous devez utiliser les types entiers de taille fixe, cela signifie que vous avez explicitement besoin que ces types soient de leurs tailles spécifiques. Autrement dit, votre code ne sera pas fonctionnel si vous ne pouvez pas obtenir d'entiers de ces tailles. Vous devez donc simplement les utiliser; si quelqu'un utilise votre code sur un compilateur qui n'a pas ces types, votre code ne sera pas compilé. Ce qui est bien, car votre code n'aurait pas fonctionné s'il avait été compilé.

Si vous n'avez pas réellement besoin d' entiers de taille fixe mais que vous les voulez simplement pour une autre raison, utilisez les int_least_*types. Si l'implémentation peut vous donner exactement cette taille, alors les least_*types auront cette taille.

Nicol Bolas
la source
4
Ce n'est pas vrai. J'ai écrit des relais stub qui implémentent operator = / etc pour les plateformes qui ne prennent pas en charge uint8_t auparavant. Mais à des fins d'efficacité et de débogage, vous ne voulez pas utiliser le passthrough à moins que ce ne soit réellement nécessaire.
TLW
@TLW: " J'ai écrit des passthroughs de bout qui implémentent operator = / etc pour les plateformes qui ne prennent pas en charge uint8_t auparavant. " OK, mais ... pourquoi? Quel code écriviez-vous qui doit être certain qu'un octet est de 8 bits (ce qui est probablement la raison pour laquelle vous l'utilisiez uint8_t), mais ce code devait en quelque sorte s'exécuter sur une plate-forme où un octet n'est pas de 8 bits (qui, en plus d'utiliser un ancienne implémentation C ++, serait la seule raison pour laquelle uint8_tne serait pas disponible)? Autrement dit, en dehors de la compatibilité ascendante, pourquoi aviez-vous besoin de faire cela?
Nicol Bolas
propriétaire ne peut donc pas en dire trop. Base de code partagée qui devait prendre en charge, entre autres, une pile matérielle plutôt excentrique. uint8_tétait beaucoup plus clair que l’approche ad hoc (et souvent interrompue) antérieure.
TLW
Si vous avez un algorithme exprimé par exemple en octets 8 bits, un passthrough est quelque chose que vous pouvez écrire une fois et qui est facile à tester. Alors que réparer chaque endroit est ad-hoc et facile à obtenir subtilement incorrect. O(1)contre l' O(n)effort. Même raison pour laquelle les gens utilisent par exemple uint16_t. Vous demandez "pourquoi ne pas utiliser uint32_t et le lancer vous-même?", Pour lequel la réponse devrait être évidente.
TLW
@TLW: " Même raison pour laquelle les gens utilisent par exemple uint16_t. " Ce n'est pas ma raison d'utiliser uint16_t. Ma raison est que je communique avec un périphérique / format / etc qui s'attend à obtenir précisément 16 bits de données formatées sous forme d'entier binaire non signé en utilisant l'endian pour ma machine, et si je ne peux pas obtenir un type qui est c'est précisément cela, alors communiquer efficacement avec elle est beaucoup plus difficile. Mon programme (et les API que j'utilise avec lui) ne peut fondamentalement pas fonctionner sur une machine qui ne fournit pas cela.
Nicol Bolas