C++
Door de implementatie bepaald gedrag
Zoeken…
Char is mogelijk niet ondertekend of ondertekend
De standaard geeft niet aan of char
moet worden ondertekend of niet ondertekend. Verschillende compilers implementeren het anders of kunnen het mogelijk maken om het te wijzigen met behulp van een opdrachtregelschakelaar.
Grootte van integrale typen
De volgende typen worden gedefinieerd als integrale typen :
-
char
- Getekende integertypen
- Niet-ondertekende gehele getallen
-
char16_t
enchar32_t
-
bool
-
wchar_t
Met uitzondering van sizeof(char)
/ sizeof(signed char)
/ sizeof(unsigned char)
, die is verdeeld tussen § 3.9.1.1 [basic.fundamental / 1] en § 5.3.3.1 [expr.sizeof], en sizeof(bool)
, die volledig door de implementatie is gedefinieerd en geen minimumgrootte heeft, worden de minimale groottevereisten van deze typen gegeven in sectie § 3.9.1 [basic.fundamental] van de norm, en worden hieronder gedetailleerd beschreven.
Grootte van char
Alle versies van de C ++ standaard specificeren, in § 5.3.3.1, dat sizeof
1
oplevert voor unsigned char
, signed char
en char
(het is door de implementatie bepaald of het char
is signed
of unsigned
is signed
).
char
is groot genoeg om 256 verschillende waarden weer te geven, geschikt voor het opslaan van UTF-8 code-eenheden.
Grootte van ondertekende en niet-ondertekende gehele getallen
De standaard specificeert, in § 3.9.1.2, dat in de lijst met standaard ondertekende integer-typen , bestaande uit signed char
, short int
, int
, long int
en long long int
, elk type minstens evenveel opslagruimte biedt als de voorgaande het in de lijst. Bovendien, zoals gespecificeerd in § 3.9.1.3, heeft elk van deze types een overeenkomstig standaard niet-ondertekend geheel getal , unsigned char
, unsigned short int
, unsigned int
, unsigned long int
en unsigned long long int
, die dezelfde grootte en uitlijning heeft als het bijbehorende ondertekende type. Bovendien, zoals gespecificeerd in § 3.9.1.1, heeft char
dezelfde grootte- en uitlijningsvereisten als zowel signed char
als unsigned char
.
Vóór C ++ 11 maakten long long
en unsigned long long
officieel geen deel uit van de C ++ standaard. Na hun introductie in C, in C99, ondersteunden veel compilers echter long long
als een uitgebreid ondertekend geheel getal , en unsigned long long
als een uitgebreid niet-ondertekend geheel getal , met dezelfde regels als de C-typen.
De norm garandeert dus dat:
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)
Specifieke minimummaten voor elk type worden niet door de standaard gegeven. In plaats daarvan heeft elk type een minimumbereik dat het kan ondersteunen, dat, zoals gespecificeerd in § 3.9.1.3, is overgenomen van de C-norm, in §5.2.4.2.1. De minimale grootte van elk type kan ruwweg worden afgeleid uit dit bereik, door het minimum aantal benodigde bits te bepalen; merk op dat voor elk gegeven platform het daadwerkelijke ondersteunde bereik van elk type groter kan zijn dan het minimum. Merk op dat voor ondertekende typen bereiken overeenkomen met iemands complement, niet het meer algemeen gebruikte twee-complement; dit om een breder scala aan platforms te laten voldoen aan de norm.
Type | Minimum bereik | Minimale bits vereist |
---|---|---|
signed char | -127 tot 127 (- (2 7 - 1) tot (2 7 - 1)) | 8 |
unsigned char | 0 tot 255 (0 tot 2 8 - 1) | 8 |
signed short | -32.767 tot 32.767 (- (2 15 - 1) tot (2 15 - 1)) | 16 |
unsigned short | 0 tot 65.535 (0 tot 2 16 - 1) | 16 |
signed int | -32.767 tot 32.767 (- (2 15 - 1) tot (2 15 - 1)) | 16 |
unsigned int | 0 tot 65.535 (0 tot 2 16 - 1) | 16 |
signed long | -2.147.483.647 tot 2.147.483.647 (- (2 31 - 1) tot (2 31 - 1)) | 32 |
unsigned long | 0 tot 4.294.967.295 (0 tot 2 32 - 1) | 32 |
Type | Minimum bereik | Minimale bits vereist |
---|---|---|
signed long long | -9.223.372.036.854.775.807 tot 9.223.372.036.854.775.807 (- (2 63 - 1) tot (2 63 - 1)) | 64 |
unsigned long long | 0 tot 18.446.744.073.709.551.615 (0 tot 2 64 - 1) | 64 |
Omdat elk type groter mag zijn dan de minimale vereiste grootte, kunnen typen verschillen in implementaties. Het meest opvallende voorbeeld hiervan is met de 64-bit datamodellen LP64 en LLP64, waarbij LLP64-systemen (zoals 64-bit Windows) 32-bit ints
en long
s hebben, en LP64-systemen (zoals 64-bit Linux) hebben 32-bit int
s en 64-bit long
s. Hierdoor kan niet worden aangenomen dat gehele typen een vaste breedte hebben voor alle platforms.
Als <cstdint>
met vaste breedte vereist zijn, gebruikt u types uit de kop <cstdint>
, maar <cstdint>
rekening mee dat de standaard het voor implementaties optioneel maakt om de exact-breedte types int8_t
, int16_t
, int32_t
, int64_t
, intptr_t
, uint8_t
, uint16_t
, uint32_t
, uint64_t
en uintptr_t
.
Grootte van char16_t
en char32_t
De maten van char16_t
en char32_t
zijn implementatiegedefinieerd, zoals gespecificeerd in § 5.3.3.1, met de bepalingen in § 3.9.1.5:
char16_t
is groot genoeg om elke UTF-16-code-eenheid te vertegenwoordigen en heeft dezelfde grootte, signatuur en uitlijning alsuint_least16_t
; het moet dus minimaal 16 bits groot zijn.char32_t
is groot genoeg om elke UTF-32-code-eenheid te vertegenwoordigen en heeft dezelfde grootte, signatuur en uitlijning alsuint_least32_t
; het moet dus minimaal 32 bits groot zijn.
Grootte van de bool
De grootte van bool
is door de implementatie bepaald en kan al dan niet 1
.
Grootte van wchar_t
wchar_t
, zoals gespecificeerd in § 3.9.1.5, is een verschillend type, waarvan het bereik van waarden elke afzonderlijke code-eenheid van de grootste uitgebreide tekenset onder de ondersteunde landinstellingen kan vertegenwoordigen. Het heeft dezelfde grootte, signatuur en uitlijning als een van de andere integrale typen, ook wel het onderliggende type genoemd . De grootte van dit type is door de implementatie bepaald, zoals gespecificeerd in § 5.3.3.1, en kan bijvoorbeeld minstens 8, 16 of 32 bits zijn; Als een systeem bijvoorbeeld Unicode ondersteunt, moet wchar_t
minimaal 32 bits zijn (een uitzondering op deze regel is Windows, waarbij wchar_t
16 bits is voor compatibiliteitsdoeleinden). Het is geërfd van de C90-norm, ISO 9899: 1990, § 4.1.5, met slechts een kleine herformulering.
Afhankelijk van de implementatie is de grootte van wchar_t
vaak, maar niet altijd, 8, 16 of 32 bits. De meest voorkomende voorbeelden hiervan zijn:
- In Unix- en Unix-achtige systemen is
wchar_t
32-bit en wordt meestal gebruikt voor UTF-32. - In Windows is
wchar_t
16-bit en wordt het gebruikt voor UTF-16. - Op een systeem dat alleen 8-bit ondersteuning heeft, is
wchar_t
8 bit.
Als Unicode-ondersteuning gewenst is, wordt het aanbevolen om char
te gebruiken voor UTF-8, char16_t
voor UTF-16 of char32_t
voor UTF-32, in plaats van wchar_t
.
Gegevensmodellen
Zoals hierboven vermeld, kunnen de breedten van gehele typen tussen platforms verschillen. De meest voorkomende modellen zijn als volgt, met maten gespecificeerd in bits:
Model | int | long | wijzer |
---|---|---|---|
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 |
Van deze modellen:
- 16-bit Windows gebruikte LP32.
- 32-bit * nix-systemen (Unix, Linux, Mac OSX en andere Unix-achtige besturingssystemen) en Windows gebruiken ILP32.
- 64-bit Windows gebruikt LLP64.
- 64-bit * nix-systemen gebruiken LP64.
Merk echter op dat deze modellen niet specifiek in de norm zelf worden vermeld.
Aantal bits in een byte
In C ++ is een byte de ruimte die wordt ingenomen door een char
object. Het aantal bits in een byte wordt gegeven door CHAR_BIT
, die wordt gedefinieerd in climits
en minimaal 8 moet zijn. Hoewel de meeste moderne systemen 8-bits bytes hebben en POSIX vereist dat CHAR_BIT
exact 8 is, zijn er enkele systemen waarbij CHAR_BIT
groter is dan 8, dwz dat een enkele byte uit 8, 16, 32 of 64 bits kan bestaan.
Numerieke waarde van een aanwijzer
Het resultaat van het casten van een pointer naar een geheel getal met reinterpret_cast
is door de implementatie gedefinieerd, maar "... is bedoeld als niet verrassend voor degenen die de adresstructuur van de onderliggende machine kennen."
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
Evenzo is de aanwijzer verkregen door conversie van een geheel getal ook door de implementatie gedefinieerd.
De juiste manier om een aanwijzer als een geheel getal op te slaan, is met de typen uintptr_t
of 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 verwijst naar C99 voor de definitie uintptr_t
(C99 standaard, 6.3.2.3):
een geheel getal zonder teken met de eigenschap dat elke geldige aanwijzer naar
void
kan worden geconverteerd naar dit type en vervolgens weer kan worden geconverteerd naar aanwijzer naarvoid
, en het resultaat wordt vergeleken met de oorspronkelijke aanwijzer.
Hoewel je voor de meeste moderne platforms kunt uitgaan van een platte adresruimte en dat rekenkunde op uintptr_t
gelijk is aan rekenkunde op char *
, is het heel goed mogelijk dat een implementatie een transformatie uitvoert bij het casten van void *
naar uintptr_t
zolang de transformatie kan worden teruggedraaid bij het terugdraaien van uintptr_t
naar void *
.
formaliteiten
Op XSI-conforme (X / Open System Interfaces) systemen zijn de
intptr_t
enuintptr_t
vereist, anders zijn ze optioneel .In de zin van de C-norm zijn functies geen objecten; door de C-standaard wordt niet gegarandeerd dat
uintptr_t
eenuintptr_t
kan bevatten. In elk geval vereist conformiteit van POSIX (2.12.3) dat:Alle typen functiewijzer moeten dezelfde weergave hebben als de te wissen typewijzer. Conversie van een functiepointer naar ongeldig * verandert niets aan de weergave. Een lege waarde * die het resultaat is van een dergelijke conversie, kan worden teruggezet naar het oorspronkelijke functiepointertype, met behulp van een expliciete cast, zonder verlies van informatie.
C99 §7.18.1:
Wanneer typefefnamen die alleen verschillen in afwezigheid of aanwezigheid van de initiële u worden gedefinieerd, zullen zij overeenkomstige ondertekende en niet-ondertekende typen aanduiden zoals beschreven in 6.2.5; een implementatie die een van deze overeenkomstige typen biedt, moet ook de andere bieden.
uintptr_t
kan zinvol zijn als u dingen wilt doen met de bits van de aanwijzer die u niet zo verstandig kunt doen met een geheel getal met teken.
Bereik van numerieke typen
De bereiken van de typen integer zijn door de implementatie bepaald. De header <limits>
biedt de sjabloon std::numeric_limits<T>
die de minimum- en maximumwaarden van alle fundamentele typen biedt. De waarden voldoen aan de garanties die door de C-norm worden geboden via de <climits>
en (> = C ++ 11) <cinttypes>
headers.
-
std::numeric_limits<signed char>::min()
gelijk aanSCHAR_MIN
, die kleiner is dan of gelijk is aan -127. -
std::numeric_limits<signed char>::max()
gelijk aanSCHAR_MAX
, dat groter is dan of gelijk is aan 127. -
std::numeric_limits<unsigned char>::max()
gelijk aanUCHAR_MAX
, dat groter is dan of gelijk aan 255. -
std::numeric_limits<short>::min()
gelijk aanSHRT_MIN
, dat kleiner is dan of gelijk is aan -32767. -
std::numeric_limits<short>::max()
gelijk aanSHRT_MAX
, dat groter is dan of gelijk is aan 32767. -
std::numeric_limits<unsigned short>::max()
gelijk aanUSHRT_MAX
, dat groter is dan of gelijk is aan 65535. -
std::numeric_limits<int>::min()
gelijk aanINT_MIN
, dat kleiner is dan of gelijk is aan -32767. -
std::numeric_limits<int>::max()
gelijk aanINT_MAX
, dat groter is dan of gelijk is aan 32767. -
std::numeric_limits<unsigned int>::max()
gelijk aanUINT_MAX
, dat groter is dan of gelijk is aan 65535. -
std::numeric_limits<long>::min()
gelijk aanLONG_MIN
, dat kleiner is dan of gelijk is aan -2147483647. -
std::numeric_limits<long>::max()
gelijk aanLONG_MAX
, dat groter is dan of gelijk is aan 2147483647. -
std::numeric_limits<unsigned long>::max()
gelijk aanULONG_MAX
, dat groter is dan of gelijk is aan 4294967295.
-
std::numeric_limits<long long>::min()
gelijk aanLLONG_MIN
, die kleiner is dan of gelijk is aan -9223372036854775807. -
std::numeric_limits<long long>::max()
gelijk aanLLONG_MAX
, dat groter is dan of gelijk is aan 9223372036854775807. -
std::numeric_limits<unsigned long long>::max()
gelijk aanULLONG_MAX
, dat groter is dan of gelijk is aan 18446744073709551615.
Voor drijvende-komma types T
, is max()
de maximale eindige waarde, terwijl min()
de minimale positieve genormaliseerde waarde is. Er zijn extra leden voorzien voor drijvende-komma-typen, die ook door de implementatie zijn gedefinieerd, maar voldoen aan bepaalde garanties die door de C-norm worden geboden via de kop <cfloat>
.
- De
digits10
geeft het aantal decimale cijfers van precisie.-
std::numeric_limits<float>::digits10
gelijk aanFLT_DIG
, wat ten minste 6 is. -
std::numeric_limits<double>::digits10
gelijk aanDBL_DIG
, wat ten minste 10 is. -
std::numeric_limits<long double>::digits10
gelijk aanLDBL_DIG
, wat ten minste 10 is.
-
- Het lid
min_exponent10
is de minimale negatieve E zodat 10 tot de macht E normaal is.-
std::numeric_limits<float>::min_exponent10
gelijk aanFLT_MIN_10_EXP
, wat maximaal -37 is. -
std::numeric_limits<double>::min_exponent10
gelijk aanDBL_MIN_10_EXP
, die maximaal -37 is.std::numeric_limits<long double>::min_exponent10
gelijk aanLDBL_MIN_10_EXP
, die maximaal -37 is.
-
- Het lid
max_exponent10
is de maximale E zodat 10 tot de macht E eindig is.-
std::numeric_limits<float>::max_exponent10
gelijk aanFLT_MIN_10_EXP
, wat ten minste 37 is. -
std::numeric_limits<double>::max_exponent10
gelijk aanDBL_MIN_10_EXP
, wat ten minste 37 is. -
std::numeric_limits<long double>::max_exponent10
gelijk aanLDBL_MIN_10_EXP
, wat ten minste 37 is.
-
- Als het lid
is_iec559
waar is, voldoet het type aan IEC 559 / IEEE 754 en wordt het bereik daarom bepaald door die norm.
Waardeweergave van drijvende komma types
De norm vereist dat long double
zo veel precisie biedt als double
, wat minstens zo veel precisie biedt als float
; en dat een long double
elke waarde kan vertegenwoordigen die een double
kan vertegenwoordigen, terwijl een double
elke waarde kan vertegenwoordigen die een float
kan vertegenwoordigen. De details van de weergave zijn echter door de implementatie bepaald.
Voor een drijvend punt type T
geeft std::numeric_limits<T>::radix
de radix aan die wordt gebruikt door de weergave van T
Als std::numeric_limits<T>::is_iec559
waar is, komt de weergave van T
overeen met een van de indelingen die zijn gedefinieerd door IEC 559 / IEEE 754.
Overloop bij conversie van geheel getal naar ondertekend geheel getal
Wanneer een ondertekend of niet-ondertekend geheel getal wordt geconverteerd naar een type met een ondertekend geheel getal en de waarde ervan niet kan worden weergegeven in het type bestemming, wordt de geproduceerde waarde door de implementatie bepaald. Voorbeeld:
// 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)
Onderliggend type (en dus de grootte) van een opsomming
Als het onderliggende type niet expliciet is opgegeven voor een niet-gescandeerd opsommingstype, wordt het bepaald op een door de implementatie gedefinieerde manier.
enum E {
RED,
GREEN,
BLUE,
};
using T = std::underlying_type<E>::type; // implementation-defined
De standaard vereist echter dat het onderliggende type van een opsomming niet groter is dan int
tenzij zowel int
als unsigned int
niet alle waarden van de opsomming kunnen weergeven. Daarom is in de bovenstaande code, T
zou kunnen zijn int
, unsigned int
, of short
, maar niet long long
, om een paar voorbeelden te geven.
Merk op dat een opsomming dezelfde grootte heeft (zoals geretourneerd door sizeof
) als het onderliggende type.