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?
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'unsigned char
ou ununsigned 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 siint8_t
correspond exactement àsigned char
(c.-à-d. un type designed char
). - autrement, la fonction de membre
int8_t
serait promue àint
et la fonction de membrebasic_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é siuint8_t
correspond exactement àunsigned char
. - autrement, puisque
int
peut représenter toutes les valeursuint8_t
, la fonction de membreuint8_t
serait promue àint
et la fonction de membrebasic_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);
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 << ...
.
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.
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
nomintN_t
désigne un type entier signé avec la largeurN
, 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
, etunsigned char
sont trois types distincts . [...] Dans n'importe quelle implémentation particulière, un objetchar
peut prendre les mêmes valeurs qu'unsigned char
ou ununsigned 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.
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", ...)
.