57 votes

Int8_t et uint8_t sont-ils destinés à se comporter comme un personnage?

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

 #include <cstdint>
#include <iostream>

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

La norme spécifie-t-elle si ce type peut ou sera un type de caractère?

25voto

Daniel Trebbien Points 18089

De § 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.fondamentaux] les états:

Il y a cinq standard signé types d'entiers: "signed char", "short int", "int", "long int"et "long long int". Dans cette liste, chaque type offre au moins autant d'espace de stockage que ceux qui le précèdent dans la liste. Il peut également être mise en œuvre définies par l' étendue entier signé types. Le standard et étendue entier signé types sont collectivement appelés entier signé types.

...

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

§ 3.9.1 indique également:

En particulier la mise en œuvre, un simple char objet peut prendre la même valeur, en signed char ou unsigned char; celui qui est de la mise en œuvre définies.

Il est tentant de conclure qu' int8_t peut être une définition de type d' char fournis char objets prennent des valeurs signées; cependant, ce n'est pas le cas à l' char n'est pas parmi la liste des entiers signés types (standard et étendu éventuellement signé types d'entiers). Voir aussi Stephan T. Lavavej commentaires sur std::make_unsigned et std::make_signed.

Par conséquent, int8_t est une définition de type d' signed char ou c'est une longue signée de type entier dont les objets occupent exactement 8 bits de stockage.

Pour répondre à votre question, cependant, vous ne devriez pas faire des hypothèses. Parce que les fonctions de ces deux formulaires x.operator<<(y) et operator<<(x,y) ont été définis, § 13.5.3 [plus.binaire] dit que nous référer au § 13.3.1.2 [plus.match.oper] pour déterminer l'interprétation de l' std::cout << i. § 13.3.1.2 à son tour, dit que la mise en œuvre sélectionne à partir de la série de fonctions candidates selon § 13.3.2 et § 13.3.3. Nous abordons ensuite le § 13.3.3.2 [plus.ics.classement] pour déterminer:

  • L' template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char) modèle sera appelé si int8_t est une Correspondance Exacte pour signed char (c'est à dire une définition de type d' signed char).
  • Sinon, l' int8_t serait promu int et de la basic_ostream<charT,traits>& operator<<(int n) de la fonction membre.

Dans le cas d' std::cout << u pour u un uint8_t objet:

  • L' template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char) modèle sera appelé si uint8_t est une Correspondance Exacte pour unsigned char.
  • Sinon, depuis int peut représenter toutes uint8_t valeurs, l' uint8_t serait promu int et de la basic_ostream<charT,traits>& operator<<(int n) de la fonction membre.

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

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

Et si vous souhaitez toujours l'impression d'un nombre:

std::cout << static_cast<int>(i);

23voto

Keith Thompson Points 85120

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

Le seul entier prédéfini types qui peuvent être de 8 bits sont char, unsigned char, et signed char. Les deux short et unsigned short doivent être d'au moins 16 bits.

Donc, int8_t doit être un typedef pour signed char ou de la plaine char (le dernier si simple char est signé).

Si vous souhaitez imprimer une int8_t de la valeur comme un nombre entier plutôt que comme un personnage, vous pouvez explicitement convertir int.

En principe, un compilateur C++ pourrait définir une 8-bits étendu de type entier (peut-être appelé quelque chose comme __int8), et de faire int8_t un typedef pour elle. La seule raison pour laquelle je peux penser à faire serait d'éviter de faire des int8_t un type de caractère. Je ne sais pas du tout compilateurs C++ qui ont réellement fait.

Les deux int8_t et étendu les types d'entiers ont été introduites en C99. Pour le C, il n'y a pas de raison particulière de définir une 8-bits étendu de type entier lorsque l' char types sont disponibles.

Mise à JOUR:

Je ne suis pas entièrement à l'aise avec cette conclusion. int8_t et uint8_t ont été introduites en C99. En C, il n'est pas particulièrement question de savoir s'ils sont de types de caractères ou pas; il n'y a pas des opérations pour lesquelles la distinction fait une vraie différence. (Même putc(), le plus faible niveau de sortie de caractères de routine en C standard, prend le caractère à imprimer comme un int argument). int8_t, et uint8_t, si ils sont définis, sera presque certainement être définis comme des types de caractères -- mais les types de caractères sont juste des petits types d'entiers.

C++ fournit des versions surchargées de operator<< pour char, signed char, et unsigned char, de sorte qu' std::cout << 'A' et std::cout << 65 produire de très différent de sortie. Plus tard, C++ adopté int8_t et uint8_t, mais de telle manière que, comme en C, ils sont presque certainement les types de caractères. Pour la plupart des opérations, cela n'a pas d'importance, pas plus qu'il n'en C, mais pour l' std::cout << ... il y a une différence, puisque ce:

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

sera probablement imprimer la lettre A plutôt que de le nombre 65.

Si vous souhaitez un comportement cohérent, ajouter 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 manque quelque chose à partir de la langue: très étroit types d'entiers qui ne sont pas de types de caractères.

Comme pour l' intention, je pourrait spéculer que les membres du comité, soit n'ont pas réfléchir à la question, ou décidé qu'il n'était pas utile de traiter. On pourrait dire (et je) que les avantages de l'ajout de l' [u]int*_t types de la norme l'emporte sur les inconvénients de leur un comportement bizarre avec std::cout << ....

6voto

Cassio Neri Points 6095

Je vais répondre à vos questions dans l'ordre inverse.

La norme de préciser si ce type peuvent ou pourront être un type de caractère?

Réponse courte: int8_t est signed char dans la plupart des plates-formes populaires (GCC/Intel/Clang sur Linux et Visual Studio sous Windows), mais peut-être autre chose dans d'autres.

La réponse longue suit.

Section 18.4.1 du C++11 Norme fournit le synopsis de l' <cstdint> qui comprend les éléments suivants

typedef entier signé de type int8_t; //optional

Plus loin dans le même article, à l'alinéa 2, il est dit

L'en-tête [<cstdint>] définit toutes les fonctions, les types et les macros le même que 7.18 dans le C standard.

où C norme C99 comme par 1.1/2:

C ++ est un langage de programmation basé sur le langage de programmation C, comme décrit dans la norme ISO/IEC 9899:1999 langages de Programmation - C (ci-après dénommé le C standard).

Par conséquent, la définition de l' int8_t se trouve dans la Section 7.18 du standard C99. Plus précisément, C99 Section 7.18.1.1 dit

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

En outre, la C99 de la Section 6.2.5/4 dit

Il y a cinq standard signé les types integer, désigné comme signed char, short int, int, long intet long long int. (Ces et d'autres types peuvent être désignés dans plusieurs autres manières, comme décrit dans 6.7.2.) Il peut également être mise en œuvre définies par l'étendue entier signé types. Le standard et étendue entier signé types sont collectivement appelés entier signé types.

Enfin, C99 Section 5.2.4.2.1 impose des tailles minimales de la norme entier signé types. À l'exclusion signed char, toutes les autres sont au moins 16 bits.

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

Les deux glibc (la bibliothèque C de GNU) et Visual Studio C de la bibliothèque de définir int8_t comme signed char. Intel et Clang, au moins sur Linux, aussi l'utilisation de la libc, et donc, la même chose s'applique à eux. Par conséquent, dans la plus populaire des plateformes int8_t est signed char.

Compte tenu de cette C++11 programme, dois-je m'attendre à voir un certain nombre ou une lettre? Ou ne pas faire hauteur des attentes?

Réponse courte: Dans la plupart des plates-formes populaires (GCC/Intel/Clang sur Linux et Visual Studio sous Windows), vous allez certainement voir la lettre 'A'. En d'autres plates-formes que vous pouvez obtenir de voir 65 . (Grâce à la Dpj pour le rappeler à moi.)

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

L'article 27.4.1 fournit le synopsis de l' <iostream>, en particulier, il dispose de la déclaration d' cout:

extern ostream cout;

Maintenant, ostream est typedef pour un modèle de spécialisation de l' 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;

Section 27.7.3.6.4 fournit 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é. Le même article précise également que l'effet de cet appel est de l'impression du caractère (pas le nombre).

Maintenant, considérons le cas où l' int8_t est une extension de type entier signé. Évidemment, la norme ne spécifie pas les surcharges d' operator<<() pour les types, mais grâce à des promotions et des conversions l'une des surcharges peut accepter l'appel. En effet, int d'au moins 16 bits de long et peut représenter toutes les valeurs de int8_t. Puis de 4,5/1 donne que l' int8_t peut être promu à l' int. D'autre part, de 4,7/1 et 4,7/2 donne qu' int8_t peut être converti à l' signed char. Enfin, 13.3.3.1.1 rendements que la promotion est favorisée par rapport à la conversion au cours de la résolution de surcharge. Par conséquent, la surcharge suivante (déclarée dans 23.7.3.1)

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

sera appelée. Cela signifie que, de ce code

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

imprime 65.

Mise à jour:

1. Corrigé le post suivant Dpj's commentaire.

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

Comme l'a dit, le standard C99 (Section 6.2.5/4 cité ci-dessus) définit 5 standard des entiers signés types (char n'est pas l'un d'eux) et permet des implémentations pour ajouter leur onw qui sont visés en tant que non-standard des entiers signés types. La norme C++ renforce cette définition dans la Section 3.9.1/2:

Il y a cinq standard signé types d'entiers : "signed char", "short int", "int", "long int" et "long long int" [...] Il peut également être mise en œuvre définies par l'étendue entier signé types. Le standard et étendue entier signé types sont collectivement appelés entier signé types.

Plus tard, dans le même article, à l'alinéa 7 dit:

Types d' bool, char, char16_t, char32_t, wchar_t, et les entiers signés et non signés types d'entiers sont collectivement appelés les 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 entier signé de type ni d'un type entier non signé et de l'Article 18.4.1 (cité ci-dessus) dit qu' int8_t, lorsqu'il est présent, est une typedef pour un entier signé de type.

Ce qui pourrait être déroutant, c'est que, selon la mise en œuvre, char peut prendre la même valeur, en signed char. En particulier, char pourrait avoir un signe mais c'est toujours pas un signed char. C'est explicitement dit dans la Section 3.9.1/1:

[...] La plaine char, signed char, et unsigned char sont de trois types distincts. [...] En particulier la mise en œuvre, un simple char objet peut prendre la même valeur, en signed char ou unsigned char; celui qui est de la mise en œuvre définies.

Cela implique également que, char est pas un nombre entier signé de type tel que défini par l'article 3.9.1/2.

3. J'avoue que mon interprétation et, plus précisément, la phrase "char n'est ni un entier signé de type ni unsigned integer" est un peu controversé.

À force de mon cas, je voudrais ajouter que Stephan T. Lavavej dit la même chose ici et Johannes Schaub - litb également utilisé la même phrase dans un commentaire sur ce post.

5voto

Rapptz Points 10135

Le brouillon 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, typedef en caractère est acceptable.

-1voto

richselian Points 403

char - signed char - unsigned char sont de types différents et un char n'est pas toujours de 8 bits. sur la plupart des plateformes, ils sont tous des entiers sur 8 bits, mais std :: ostream définit uniquement la version de caractère de >> pour des comportements tels que scanf("%c", ...) .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X