C++
Comportement défini par la mise en œuvre
Recherche…
Char peut être non signé ou signé
La norme ne spécifie pas si char
doit être signé ou non signé. Différents compilateurs l'implémentent différemment ou peuvent le modifier à l'aide d'un commutateur de ligne de commande.
Taille des types intégraux
Les types suivants sont définis comme types intégraux :
-
char
- Types d'entiers signés
- Types entiers non signés
-
char16_t
etchar32_t
-
bool
-
wchar_t
À l'exception de sizeof(char)
/ sizeof(signed char)
/ sizeof(unsigned char)
, qui est divisé entre le § 3.9.1.1 [basic.fundamental / 1] et le § 5.3.3.1 [expr.sizeof], et sizeof(bool)
, qui est entièrement défini par la mise en œuvre et n’a pas de taille minimale, les exigences de taille minimale de ces types sont données dans la section § 3.9.1 [élément fondamental] de la norme et doivent être détaillées ci-dessous.
Taille de char
Toutes les versions du C de la norme spécifient, au § 5.3.3.1, que sizeof
rendements 1
pour unsigned char
, signed char
, et l' char
(il est défini par l' implémentation si le char
type est signed
ou unsigned
).
char
est assez grand pour représenter 256 valeurs différentes, pour pouvoir stocker des unités de code UTF-8.
Taille des types d'entiers signés et non signés
La norme spécifie, au § 3.9.1.2, que dans la liste des types entiers signés standard , consistant en un caractère signed char
, short int
, un int
, un long int
et un long long int
, chaque type fournira au moins autant de stockage que ceux précédents dans la liste. De plus, comme spécifié au § 3.9.1.3, chacun de ces types a un type d'entier non signé standard correspondant, un caractère non unsigned char
, un unsigned short int
, un unsigned int
, un unsigned long int
et unsigned long long int
son type signé correspondant. En outre, comme spécifié au § 3.9.1.1, char
a la même taille et les exigences d' alignement à la fois comme signed char
et unsigned char
.
Avant C ++ 11, long long
et unsigned long long
ne faisaient pas officiellement partie du standard C ++. Cependant, après leur introduction à C, en C99, de nombreux compilateurs prenaient en charge long long
entier signé étendu et ne signaient unsigned long long
tant que type entier non signé étendu , avec les mêmes règles que les types C.
La norme garantit ainsi que:
1 == sizeof(char) == sizeof(signed char) == sizeof(unsigned char)
<= sizeof(short) == sizeof(unsigned short)
<= sizeof(int) == sizeof(unsigned int)
<= sizeof(long) == sizeof(unsigned long)
<= sizeof(long long) == sizeof(unsigned long long)
Les tailles minimales spécifiques pour chaque type ne sont pas données par la norme. Au lieu de cela, chaque type a une plage minimale de valeurs qu'il peut prendre en charge, à savoir, comme spécifié au § 3.9.1.3, hérité du standard C, au § 5.2.4.2.1. La taille minimale de chaque type peut être approximativement déduite de cette plage, en déterminant le nombre minimal de bits requis; notez que pour toute plate-forme donnée, la plage prise en charge réelle de tout type peut être supérieure au minimum. Notez que pour les types signés, les plages correspondent à son complément, pas au complément à deux plus communément utilisé; Cela permet à un plus large éventail de plates-formes de se conformer à la norme.
Type | Portée minimale | Bits minimum requis |
---|---|---|
signed char | -127 à 127 (- (2 7 - 1) à (2 7 - 1)) | 8 |
unsigned char | 0 à 255 (0 à 2 8 - 1) | 8 |
signed short | -32767 à 32767 (- (février 15 à 1) à (15 à 1 février)) | 16 |
unsigned short | 0 à 65 535 (0 à 2 16 - 1) | 16 |
signed int | -32 767 à 32 767 (- (2 15 - 1) à (2 15 - 1)) | 16 |
unsigned int | 0 à 65 535 (0 à 2 16 - 1) | 16 |
signed long | -2 147 483 647 à 2 147 483 647 (- (2 31 - 1) à (2 31 - 1)) | 32 |
unsigned long | 0 à 4 294 967 295 (0 à 2 32 - 1) | 32 |
Type | Portée minimale | Bits minimum requis |
---|---|---|
signed long long | -9 223 372 036 854 775 807 à 9 223 372 036 854 775 807 (- (2 63 - 1) à (2 63 - 1)) | 64 |
unsigned long long | 0 à 18,446,744,073,709,551,615 (0 à 2 64-1 ) | 64 |
Chaque type pouvant être supérieur à la taille minimale requise, les types peuvent varier en taille entre les implémentations. L'exemple le plus notable de c'est avec les modèles de données 64 bits LP64 et LLP64, où les systèmes de LLP64 (tels que Windows 64 bits) ont 32 bits ints
et long
s et des systèmes LP64 (tels que Linux 64 bits) ont 32 bits int
et 64 bits long
s. De ce fait, les types d'entiers ne peuvent pas être supposés avoir une largeur fixe sur toutes les plates-formes.
Si les entiers avec largeur fixe sont nécessaires, les types d'utilisation de la <cstdint>
en- tête, mais notez que la norme rend facultative pour les implémentations de soutenir les types exacts de largeur int8_t
, int16_t
, int32_t
, int64_t
, intptr_t
, uint8_t
, uint16_t
, uint32_t
, uint64_t
et uintptr_t
.
Taille de char16_t
et char32_t
Les tailles de char16_t
et char32_t
sont définies par l'implémentation, comme spécifié au § 5.3.3.1, avec les stipulations du § 3.9.1.5:
char16_t
est assez grand pour représenter n'importe quelle unité de code UTF-16 et a la même taille, la même signature et le même alignement queuint_least16_t
; il faut donc au moins 16 bits.char32_t
est assez grand pour représenter n'importe quelle unité de code UTF-32 et a la même taille, la même signature et le même alignement queuint_least32_t
; il faut donc au moins 32 bits.
Taille de bool
La taille de bool
est définie par l'implémentation et peut ou non être 1
.
Taille de wchar_t
wchar_t
, comme spécifié au § 3.9.1.5, est un type distinct, dont la plage de valeurs peut représenter chaque unité de code distincte du plus grand jeu de caractères étendu parmi les paramètres régionaux pris en charge. Il a la même taille, la même signature et le même alignement que l'un des autres types intégraux, connu sous le nom de son type sous-jacent . La taille de ce type est définie par la mise en œuvre, comme spécifié au § 5.3.3.1, et peut être, par exemple, d'au moins 8, 16 ou 32 bits; Si un système prend en charge Unicode, par exemple, wchar_t
doit comporter au moins 32 bits (une exception à cette règle est Windows, où wchar_t
correspond à 16 bits à des fins de compatibilité). Il est hérité de la norme C90, ISO 9899: 1990 § 4.1.5, avec seulement une reformulation mineure.
Selon l'implémentation, la taille de wchar_t
est souvent, mais pas toujours, 8, 16 ou 32 bits. Les exemples les plus courants sont les suivants:
- Dans les systèmes Unix et Unix,
wchar_t
est 32 bits et est généralement utilisé pour UTF-32. - Dans Windows,
wchar_t
est 16 bits et est utilisé pour UTF-16. - Sur un système qui ne prend en charge que 8 bits,
wchar_t
8 bits.
Si le support Unicode est souhaité, il est recommandé d'utiliser char
pour UTF-8, char16_t
pour UTF-16 ou char32_t
pour UTF-32, au lieu d'utiliser wchar_t
.
Modèles de données
Comme mentionné ci-dessus, les largeurs des types entiers peuvent différer entre les plates-formes. Les modèles les plus courants sont les suivants, avec des tailles spécifiées en bits:
Modèle | int | long | aiguille |
---|---|---|---|
LP32 (2/4/4) | 16 | 32 | 32 |
ILP32 (4/4/4) | 32 | 32 | 32 |
LLP64 (4/4/8) | 32 | 32 | 64 |
LP64 (4/8/8) | 32 | 64 | 64 |
Sur ces modèles:
- Windows 16 bits utilisé LP32.
- Les systèmes nix 32 bits * (Unix, Linux, Mac OSX et autres systèmes d'exploitation de type Unix) et Windows utilisent ILP32.
- Windows 64 bits utilise LLP64.
- Les systèmes 64 bits * nix utilisent LP64.
Notez cependant que ces modèles ne sont pas spécifiquement mentionnés dans la norme elle-même.
Nombre de bits dans un octet
En C ++, un octet est l'espace occupé par un objet char
. Le nombre de bits dans un octet est donné par CHAR_BIT
, qui est défini dans les climits
et doit être d'au moins 8. Alors que la plupart des systèmes modernes ont des octets de 8 bits, et POSIX exige que CHAR_BIT
soit exactement 8, il existe certains systèmes où CHAR_BIT
est supérieur à 8, c'est-à-dire qu'un seul octet peut être composé de 8, 16, 32 ou 64 bits.
Valeur numérique d'un pointeur
Le résultat du lancement d'un pointeur sur un entier à l'aide de reinterpret_cast
est défini par l'implémentation, mais "... est destiné à être sans surprise pour ceux qui connaissent la structure d'adressage de la machine sous-jacente."
int x = 42;
int* p = &x;
long addr = reinterpret_cast<long>(p);
std::cout << addr << "\n"; // prints some numeric address,
// probably in the architecture's native address format
De même, le pointeur obtenu par conversion à partir d'un entier est également défini par l'implémentation.
La manière correcte de stocker un pointeur en tant uintptr_t
consiste à utiliser les types uintptr_t
ou intptr_t
:
// `uintptr_t` was not in C++03. It's in C99, in <stdint.h>, as an optional type
#include <stdint.h>
uintptr_t uip;
// There is an optional `std::uintptr_t` in C++11
#include <cstdint>
std::uintptr_t uip;
C ++ 11 fait référence à C99 pour la définition de uintptr_t
(norme C99, 6.3.2.3):
un type d'entier non signé avec la propriété que tout pointeur valide à
void
peut être converti en ce type, puis reconverti en pointeur survoid
, et le résultat sera égal au pointeur d'origine.
Alors que, pour la majorité des plates - formes modernes, vous pouvez supposer un espace d'adressage plat et que l' arithmétique sur uintptr_t
équivaut à l' arithmétique sur char *
, il est tout à fait possible pour une mise en œuvre pour réaliser une transformation lors de la coulée void *
à uintptr_t
tant la transformation peut être inversé lors du retour de uintptr_t
pour void *
.
Techniques
Sur les systèmes
intptr_t
XSI (X / Open System Interfaces), les typesintptr_t
etuintptr_t
sont obligatoires, sinon ils sont facultatifs .Au sens de la norme C, les fonctions ne sont pas des objets; le standard C ne garantit pas que
uintptr_t
puisse contenir un pointeur de fonction. Quoi qu’il en soit, la conformité POSIX (2.12.3) nécessite que:Tous les types de pointeurs de fonction doivent avoir la même représentation que le pointeur de type à annuler. La conversion d'un pointeur de fonction en void * ne modifie pas la représentation. Une valeur vide * résultant d'une telle conversion peut être reconvertie dans le type de pointeur de fonction d'origine, en utilisant une conversion explicite, sans perte d'informations.
C99 §7.18.1:
Lorsque des noms typedef ne différant que par l'absence ou la présence de l'u initial sont définis, ils doivent indiquer les types signés et non signés correspondants, comme décrit au 6.2.5; une implémentation fournissant l'un de ces types correspondants fournira également l'autre.
uintptr_t
peut avoir un sens si vous voulez faire des choses sur les bits du pointeur que vous ne pouvez pas faire aussi intelligemment avec un entier signé.
Plages de types numériques
Les plages des types entiers sont définies par l'implémentation. L'en-tête <limits>
fournit le modèle std::numeric_limits<T>
qui fournit les valeurs minimales et maximales de tous les types fondamentaux. Les valeurs satisfont aux garanties fournies par le standard C via les en- <climits>
et (> = C ++ 11) <cinttypes>
.
-
std::numeric_limits<signed char>::min()
est égal àSCHAR_MIN
, qui est inférieur ou égal à -127. -
std::numeric_limits<signed char>::max()
est égal àSCHAR_MAX
, qui est supérieur ou égal à 127. -
std::numeric_limits<unsigned char>::max()
est égal àUCHAR_MAX
, qui est supérieur ou égal à 255. -
std::numeric_limits<short>::min()
est égal àSHRT_MIN
, qui est inférieur ou égal à -32767. -
std::numeric_limits<short>::max()
est égal àSHRT_MAX
, qui est supérieur ou égal à 32767. -
std::numeric_limits<unsigned short>::max()
est égal àUSHRT_MAX
, qui est supérieur ou égal à 65535. -
std::numeric_limits<int>::min()
est égal àINT_MIN
, qui est inférieur ou égal à -32767. -
std::numeric_limits<int>::max()
est égal àINT_MAX
, qui est supérieur ou égal à 32767. -
std::numeric_limits<unsigned int>::max()
est égal àUINT_MAX
, qui est supérieur ou égal à 65535. -
std::numeric_limits<long>::min()
est égal àLONG_MIN
, qui est inférieur ou égal à -2147483647. -
std::numeric_limits<long>::max()
est égal àLONG_MAX
, qui est supérieur ou égal à 2147483647. -
std::numeric_limits<unsigned long>::max()
est égal àULONG_MAX
, qui est supérieur ou égal à 4294967295.
-
std::numeric_limits<long long>::min()
est égal àLLONG_MIN
, qui est inférieur ou égal à -9223372036854775807. -
std::numeric_limits<long long>::max()
est égal àLLONG_MAX
, qui est supérieur ou égal à 9223372036854775807. -
std::numeric_limits<unsigned long long>::max()
est égal àULLONG_MAX
, qui est supérieur ou égal à 18446744073709551615.
Pour les types à virgule flottante T
, max()
est la valeur finie maximale tandis que min()
est la valeur normalisée positive minimale. Des membres supplémentaires sont fournis pour les types à virgule flottante, qui sont également définis par l'implémentation mais satisfont à certaines garanties fournies par le standard C via l'en-tête <cfloat>
.
- Le membre
digits10
donne le nombre de chiffres décimaux de précision.-
std::numeric_limits<float>::digits10
est égal àFLT_DIG
, qui est au moins 6. -
std::numeric_limits<double>::digits10
est égal àDBL_DIG
, soit au moins 10. -
std::numeric_limits<long double>::digits10
est égal àLDBL_DIG
, soit au moins 10.
-
- Le membre
min_exponent10
est le minimum négatif E tel que 10 à la puissance E est normal.-
std::numeric_limits<float>::min_exponent10
est égal àFLT_MIN_10_EXP
, soit au maximum -37. -
std::numeric_limits<double>::min_exponent10
est égal àDBL_MIN_10_EXP
, soit au maximum -37.std::numeric_limits<long double>::min_exponent10
est égal àLDBL_MIN_10_EXP
, soit au maximum -37.
-
- Le membre
max_exponent10
est le maximum E tel que 10 à la puissance E est fini.-
std::numeric_limits<float>::max_exponent10
est égal àFLT_MIN_10_EXP
, soit au moins 37. -
std::numeric_limits<double>::max_exponent10
est égal àDBL_MIN_10_EXP
, soit au moins 37. -
std::numeric_limits<long double>::max_exponent10
est égal àLDBL_MIN_10_EXP
, soit au moins 37.
-
- Si le membre
is_iec559
est vrai, le type est conforme à la norme IEC 559 / IEEE 754 et sa plage est donc déterminée par cette norme.
Représentation de la valeur des types à virgule flottante
Le standard exige que le long double
fournisse au moins autant de précision que le double
, ce qui fournit au moins autant de précision que le float
; et qu'un long double
peut représenter n'importe quelle valeur qu'un double
peut représenter, tandis qu'un double
peut représenter n'importe quelle valeur qu'un float
peut représenter. Les détails de la représentation sont cependant définis par la mise en œuvre.
Pour un type à virgule flottante T
, std::numeric_limits<T>::radix
spécifie la base utilisée par la représentation de T
Si std::numeric_limits<T>::is_iec559
est vrai, alors la représentation de T
correspond à l'un des formats définis par la norme IEC 559 / IEEE 754.
Débordement lors de la conversion d'un entier en entier signé
Lorsqu'un entier signé ou non signé est converti en un type entier signé et que sa valeur n'est pas représentable dans le type de destination, la valeur produite est définie par l'implémentation. Exemple:
// Suppose that on this implementation, the range of signed char is -128 to +127 and
// the range of unsigned char is 0 to 255
int x = 12345;
signed char sc = x; // sc has an implementation-defined value
unsigned char uc = x; // uc is initialized to 57 (i.e., 12345 modulo 256)
Type sous-jacent (et donc taille) d'un enum
Si le type sous-jacent n'est pas explicitement spécifié pour un type d'énumération non segmenté, il est déterminé d'une manière définie par l'implémentation.
enum E {
RED,
GREEN,
BLUE,
};
using T = std::underlying_type<E>::type; // implementation-defined
Toutefois, la norme exige que le type sous-jacent d’une énumération ne soit pas supérieur à int
moins que int
et unsigned int
ne puissent pas représenter toutes les valeurs de l’énumération. Par conséquent, dans le code ci-dessus, T
pourrait être int
, unsigned int
ou short
, mais pas long long
, pour donner quelques exemples.
Notez qu'une énumération a la même taille (renvoyée par sizeof
) que son type sous-jacent.