Est-ce que int8 t et uint8 t sont des types d'omble?

étant donné ce programme C++11, dois-je m'attendre à voir un nombre ou une lettre? Ou ne pas faire hauteur des attentes?

#include <cstdint>
#include <iostream>

int main()
{
    int8_t i = 65;
    std::cout << i;
}

est-ce que la norme spécifie si ce type peut ou sera un type de caractère?

54
demandé sur Drew Dormann 2013-04-10 00:20:03

5 réponses

de l'article 18.4.1 [cstdint.syn] du C++0x FDIS (N3290), int8_t est une option de définition de type qui est spécifié comme suit:

namespace std {
  typedef signed integer type int8_t;  // optional
  //...
} // namespace std

§ 3.9.1 [de base.fundamental]:

il y a cinq types entiers standard signés : " signed char ", " short int ", " int ", " long int ", et " long long int ". Dans cette liste, chaque type fournit au moins autant de stockage que ceux précédent dans la liste. Il peut également y avoir des types entiers étendus signés définis par la mise en œuvre . Les types entiers signés standard et étendu sont collectivement appelés types entiers signés .

...

Types bool , char , char16_t , char32_t , wchar_t , et les types entiers signés et non signés sont collectivement appelés types intégraux . Un synonyme de type intégral est type entier .

§ 3.9.1 dispose également:

dans n'importe quelle implémentation particulière, un objet char peut prendre soit les mêmes valeurs qu'un signed char ou un unsigned char ; lequel est implémentation-défini.

il est tentant de conclure que int8_t peut être un type de char fournit char les objets prennent des valeurs signées; cependant, ce n'est pas le cas car char ne figure pas dans la liste des types entiers signés (types entiers standard et éventuellement étendus signés). Voir aussi les commentaires de Stephan T. Lavavej sur std::make_unsigned et std::make_signed .

par conséquent, soit int8_t est un typedef de signed char ou il est un type entier signé étendu dont les objets occupent exactement 8 bits de stockage.

pour répondre à votre question, cependant, vous ne devez pas faire de suppositions. Étant donné que les fonctions des deux formulaires x.operator<<(y) et operator<<(x,y) ont été définies, § 13.5.3 [over.binaire] dit que nous référer au § 13.3.1.2 [plus.correspondre.oper] pour déterminer l'interprétation de std::cout << i . Le paragraphe 13.3.1.2 dit à son tour que la mise en œuvre sélectionne parmi l'ensemble des fonctions candidates conformément aux paragraphes 13.3.2 et 13.3.3. Nous nous référons ensuite à l'article 13.3.3.2. [plus.ics.rang] pour déterminer que:

  • le modèle template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char) s'appellerait si int8_t correspond exactement à signed char (c.-à-d. un type de signed char ).
  • autrement, la fonction de membre int8_t serait promue à int et la fonction de membre basic_ostream<charT,traits>& operator<<(int n) serait appelée.

dans le cas de std::cout << u pour u a uint8_t objet:

  • le modèle template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char) sera appelé si uint8_t correspond exactement à unsigned char .
  • autrement, puisque int peut représenter toutes les valeurs uint8_t , la fonction de membre uint8_t serait promue à int et la fonction de membre basic_ostream<charT,traits>& operator<<(int n) serait appelée.

si vous voulez toujours imprimer un caractère, l'option la plus sûre et la plus claire est:

std::cout << static_cast<signed char>(i);

et si vous voulez toujours imprimer un numéro:

std::cout << static_cast<int>(i);
25
répondu Daniel Trebbien 2013-04-24 11:11:14

int8_t est exactement 8 bits de large (si elle existe).

les seuls types entiers prédéfinis qui peuvent être 8 bits sont char , unsigned char , et signed char . Les deux short et unsigned short doivent être d'au moins 16 bits.

So int8_t doit être dactylographié pour signed char ou char (ce dernier si char est signé).

si vous voulez imprimer un int8_t valeur comme un entier plutôt que comme un caractère, vous pouvez le convertir explicitement en int .

en principe, un compilateur C++ pourrait définir un 8-bit type entier étendu (peut-être appelé quelque chose comme __int8 ), et faire int8_t un typedef pour lui. La seule raison pour laquelle je peux penser à faire serait d'éviter de faire des int8_t un type de caractère. Je ne connais aucun compilateur C++ qui ait fait ça.

les types int8_t et "extended integer" ont été introduits en C99. Pour C, il n'y a pas de raison particulière de définir un type entier étendu de 8 bits lorsque les types char sont disponibles.

mise à JOUR :

Je ne suis pas entièrement à l'aise avec cette conclusion. int8_t et uint8_t ont été introduits en C99. En C, peu importe qu'il s'agisse de personnages ou non.; il n'y a pas d'opérations pour lesquelles la distinction fait une réelle différence. (Même putc() , le plus bas niveau de la routine de sortie de caractère dans la norme C, prend le caractère à imprimer comme un int argument). int8_t , et uint8_t , s'ils sont définis, seront presque certainement définis comme des types de caractères -- mais les types de caractères sont juste de petits types entiers.

C++ fournit des versions spécifiques surchargées de operator<< pour char , signed char , et unsigned char , de sorte que std::cout << 'A' et std::cout << 65 produisent des résultats très différents. Plus tard , C++ a adopté int8_t et uint8_t , mais de telle manière que, comme en C, ils sont presque certainement des types de caractères. Pour la plupart des opérations, cela n'a pas plus d'importance qu'en C, mais pour std::cout << ... Cela fait une différence, puisque ceci:

uint8_t x = 65;
std::cout << x;

affichera probablement la lettre A plutôt que le numéro 65 .

si vous voulez un comportement cohérent, ajoutez un plâtre:

uint8_t x = 65;
std::cout << int(x); // or static_cast<int>(x) if you prefer

je pense que la racine du problème est qu'il y a quelque chose qui manque dans la langue: des types entiers très étroits qui ne sont pas des types de caractères.

quant au intention , je peux supposer que les membres du comité soit n'ont pas pensé à la question, ou a décidé qu'il n'était pas la peine d'aborder. On pourrait soutenir (et je le ferais) que le les avantages d'ajouter les types [u]int*_t à la norme l'emportent sur les inconvénients de leur comportement plutôt étrange avec std::cout << ... .

24
répondu Keith Thompson 2013-04-11 01:58:03

la copie de travail que j'ai, n3376, spécifie dans [cstdint.syn] § 18.4.1 que les types int sont typiquement des typedefs.

namespace std {
typedef signed integer type int8_t; // optional
typedef signed integer type int16_t; // optional
typedef signed integer type int32_t; // optional
typedef signed integer type int64_t; // optional
typedef signed integer type int_fast8_t;
typedef signed integer type int_fast16_t;
typedef signed integer type int_fast32_t;
typedef signed integer type int_fast64_t;
typedef signed integer type int_least8_t;
typedef signed integer type int_least16_t;
typedef signed integer type int_least32_t;
typedef signed integer type int_least64_t;
typedef signed integer type intmax_t;
typedef signed integer type intptr_t; // optional
typedef unsigned integer type uint8_t; // optional
typedef unsigned integer type uint16_t; // optional
typedef unsigned integer type uint32_t; // optional
typedef unsigned integer type uint64_t; // optional
typedef unsigned integer type uint_fast8_t;
typedef unsigned integer type uint_fast16_t;
typedef unsigned integer type uint_fast32_t;
typedef unsigned integer type uint_fast64_t;
typedef unsigned integer type uint_least8_t;
typedef unsigned integer type uint_least16_t;
typedef unsigned integer type uint_least32_t;
typedef unsigned integer type uint_least64_t;
typedef unsigned integer type uintmax_t;
typedef unsigned integer type uintptr_t; // optional
} // namespace std

étant donné que la seule exigence est qu'il doit être de 8 bits, alors dactylographié à un char est acceptable.

5
répondu Rapptz 2013-04-09 20:24:50

je répondrai à vos questions dans l'ordre inverse.

est-ce que la norme spécifie si ce type peut ou sera un type de caractère?

Short answer : int8_t est signed char dans les plates-formes les plus populaires (GCC/Intel/Clang sur Linux et Visual Studio sur Windows), mais pourrait être quelque chose d'autre dans d'autres.

la longue réponse suit.

la Section 18.4.1 de la norme C++11 fournit le synopsis de <cstdint> qui comprend ce qui suit:"

typedef type entier signé int8_t; //optional

plus loin dans la même section, paragraphe 2, Il est dit

l'en-tête [ <cstdint> ] définit toutes les fonctions, les types et les macros comme 7.18 dans la norme C .

où c signifie C99 selon 1.1 / 2:

c ++ est un langage de programmation universel basé sur le langage de programmation C tel que décrit dans ISO/IEC 9899:1999 langages de programmation - C (ci-après dénommé C standard ).

par conséquent, la définition de int8_t se trouve à L'article 7.18 de la norme C99. Plus précisément, la Section 7.18.1.1 de C99 stipule:

le typedef nom intN_t désigne un type entier signé avec la largeur N , pas de bits de rembourrage, et une représentation de complément de deux. Ainsi, int8_t dénote un type entier signé avec une largeur d'exactement 8 bits .

de plus, la Section 6.2.5/4 de C99 dit

il y a cinq types standards d'entiers signés , désignés comme char signé , short int , int , long int , et long long int . (Ces types et d'autres peuvent être désignés de plusieurs autres façons, comme décrit au 6.7.2.) Il peut aussi y avoir "implémentation-defined extended signed integer types . Le standard et étendue entier signé types sont collectivement appelés entier signé de types .

enfin, la Section 5.2.4.2.1 de la norme C99 impose des tailles minimales pour les types d'entiers signés standard. À l'exclusion de signed char , tous les autres ont une longueur d'au moins 16 bits.

par conséquent, int8_t est soit signed char ou un 8 bits de long étendu (non standard) type entier signé.

tous les deux glibc (le GNU C library) et Visual Studio C library définissent int8_t comme signed char . Intel et Clang, du moins sous Linux, utilisent aussi la libc et par conséquent, la même chose s'applique à eux. Par conséquent, dans les plates-formes les plus populaires int8_t est signed char .

étant donné ce programme C++11, dois-je m'attendre à voir un nombre ou une lettre? Ou ne pas faire hauteur des attentes?

réponse courte : dans le plus populaire plates-formes (GCC/Intel/Clang sur Linux et Visual Studio sur Windows) vous verrez certainement la lettre "A". Dans d'autres plates-formes, vous pourriez obtenir voir 65 cependant. (Merci à DyP pour m'avoir fait remarquer cela.)

Dans la suite, toutes les références sont pour le C++11 standard (projet actuel, N3485).

la Section 27.4.1 fournit le synopsis de <iostream> , en particulier, elle énonce la déclaration de cout :

extern ostream cout;

Maintenant, ostream est un typedef pour un modèle de spécialisation de basic_ostream conformément à l'Article 27.7.1:

template <class charT, class traits = char_traits<charT> >
class basic_ostream;

typedef basic_ostream<char> ostream;

la Section 27.7.3.6.4 contient la déclaration suivante:

template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c);

Si int8_t est signed char alors c'est cette surcharge qui va être appelé. La même section spécifie également que l'effet de cet appel est d'imprimer le caractère (et non le numéro).

considérons maintenant le cas où int8_t est un type entier étendu signé. De toute évidence, la norme ne spécifie pas de surcharges de operator<<() pour les types non standard, mais grâce à des promotions et des conversions, l'un des surcharges fournies pourrait accepter l'appel. En effet, int est d'au moins 16 bits de long et peut représenter toutes les valeurs de int8_t . Puis 4.5 / 1 donne que int8_t peut être promu à int . D'autre part, 4.7/1 et 4.7/2 donne que int8_t peut être converti en signed char . Enfin, le paragraphe 13.3.3.1.1 indique que la promotion est favorisée par rapport à la conversion pendant la résolution de la surcharge. Par conséquent, la surcharge suivante (déclarée en 23.7.3.1)

basic_ostream& basic_ostream::operator<<(int n);

sera appelé. Cela signifie que, ce code

int8_t i = 65;
std::cout << i;

imprime 65 .

mise à jour:

1 . Corrigé le billet suivant le commentaire de DyP .

2 . Ajouté les commentaires suivants sur la possibilité de int8_t être un typedef pour char .

comme dit, la norme C99 (Section 6.2.5/4 citée ci-dessus) définit 5 les types d'entiers signés standard ( char n'est pas l'un d'entre eux) et permet aux implémentations d'ajouter leur onw qui sont référencés comme des types d'entiers signés non standard. La norme C++ renforce cette définition dans la Section 3.9.1 / 2:

il existe cinq types d'entiers signés standard:" signed char"," short int"," int"," long int", et" long long int" [...] Il peut également y avoir des types entiers étendus signés définis par la mise en œuvre. La norme et étendue les types entiers signés sont collectivement appelés les types entiers signés .

plus tard, dans la même section, le paragraphe 7 dit:

Types bool , char , char16_t , char32_t , wchar_t , et les types entiers signés et non signés sont collectivement appelés types intégraux . Synonyme de type intégral est de type entier .

par conséquent, char est un type entier mais char n'est ni un type entier signé ni un type entier non signé et la Section 18.4.1 (citée ci-dessus) dit que int8_t , lorsqu'il est présent, est un typedef pour un type entier signé.

ce qui pourrait prêter à confusion est que, selon l'implémentation, char peut prendre les mêmes valeurs que un signed char . En particulier, char pourrait avoir un signe, mais ce n'est toujours pas un signed char . Ceci est dit explicitement dans la Section 3.9.1 / 1:

[...] char , signed char , et unsigned char sont trois types distincts . [...] Dans n'importe quelle implémentation particulière, un objet char peut prendre les mêmes valeurs qu'un signed char ou un unsigned char ; lequel est défini par implémentation.

cela implique également que char est et non un type entier signé tel que défini par 3.9.1/2.

3 . Je reconnais que mon interprétation et, en particulier, la phrase char n'est ni un type entier signé ni un type entier non signé" est un peu controversée.

pour renforcer mon cas, je voudrais ajouter que Stephan T. Lavavej a dit le très même chose ici et Johannes Schaub - litb également utilisé la même phrase dans un commentaire sur ce post.

5
répondu Cassio Neri 2017-05-23 12:25:57

char / signed char / unsigned char sont trois types différents, et un char n'est pas toujours 8 bits. sur la plupart des plates-formes, ils sont tous de 8 bits entier, mais std::ostream seulement défini la version de charge de >> pour les comportements comme scanf("%c", ...) .

-1
répondu richselian 2013-04-14 12:28:30