C++
Implementierungsdefiniertes Verhalten
Suche…
Char ist möglicherweise nicht signiert oder signiert
Der Standard gibt nicht an, ob char
signiert oder nicht signiert sein soll. Verschiedene Compiler implementieren sie unterschiedlich oder erlauben es möglicherweise, sie mit einem Befehlszeilenschalter zu ändern.
Größe der ganzzahligen Typen
Die folgenden Typen sind als integrale Typen definiert:
-
char
- Signierte Integer-Typen
- Vorzeichenlose Integer-Typen
-
char16_t
undchar32_t
-
bool
-
wchar_t
Mit Ausnahme von sizeof(char)
/ sizeof(signed char)
/ sizeof(unsigned char)
Zeichen sizeof(unsigned char)
, das sich in § 3.9.1.1 [basic.fundamental / 1] und § 5.3.3.1 [expr.sizeof] und sizeof(bool)
, das vollständig implementierungsdefiniert ist und keine Mindestgröße hat, sind die Mindestgrößenanforderungen dieser Typen in Abschnitt 3.9.1 [basic.fundamental] der Norm angegeben und werden im Folgenden detailliert beschrieben.
Größe des char
Alle Versionen des C ++ Standard angeben, in § 5.3.3.1, dass sizeof
Ausbeuten 1
für unsigned char
, signed char
und char
(es ist festgelegt , ob die Umsetzung char
Typ wird signed
oder unsigned
).
char
ist groß genug, um 256 verschiedene Werte darzustellen, um UTF-8-Codeeinheiten speichern zu können.
Größe der vorzeichenbehafteten und vorzeichenlosen Integer-Typen
Der Standard legt in § 3.9.1.2 fest, dass jeder Typ in der Liste der signierten Integer-Typen mit Vorzeichen , bestehend aus signed char
, short int
, int
, long int
und long long int
, mindestens so viel Speicherplatz bereitstellen wird wie die vorhergehenden es in der Liste. Wie in § 3.9.1.3 angegeben, hat jeder dieser Typen außerdem einen entsprechenden vorzeichenlosen Integer-Typ mit unsigned char
, unsigned char
, unsigned short int
, unsigned int
, unsigned long int
und ein unsigned long long int
, das dieselbe Größe und Ausrichtung wie hat der entsprechende signierte Typ. Gemäß § 3.9.1.1 hat char
die gleichen Größen- und Ausrichtungsanforderungen wie signed char
und unsigned char
.
long long
und unsigned long long
waren vor C ++ 11 nicht offiziell Teil des C ++ - Standards. Nach der Einführung von C in C99 unterstützten viele Compiler jedoch den long long
Typ als Ganzzahl mit unsigned long long
und den unsigned long long
als unsigned long long
Ganzzahl mit Vorzeichen und den gleichen Regeln wie die C-Typen.
Der Standard garantiert somit:
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)
Bestimmte Mindestgrößen für jeden Typ sind in der Norm nicht angegeben. Stattdessen verfügt jeder Typ über einen minimalen Wertebereich, den er unterstützen kann. Dieser wird, wie in § 3.9.1.3 angegeben, vom C-Standard in §5.2.4.2.1 übernommen. Die Mindestgröße jedes Typs kann grob aus diesem Bereich abgeleitet werden, indem die erforderliche Mindestanzahl von Bits bestimmt wird. Beachten Sie, dass für jede Plattform der tatsächlich unterstützte Bereich eines Typs größer sein kann als das Minimum. Beachten Sie, dass die Bereiche für vorzeichenbehaftete Typen einem Komplement entsprechen, nicht dem am häufigsten verwendeten Zweierkomplement; Dies ermöglicht eine breitere Palette von Plattformen, um den Standard zu erfüllen.
Art | Mindestbereich | Minimale Bits erforderlich |
---|---|---|
signed char | -127 bis 127 (- (2 7 - 1) bis (2 7 - 1)) | 8 |
unsigned char | 0 bis 255 (0 bis 2 8 - 1) | 8 |
signed short | -32,767 bis 32,767 (- (2 15 - 1) bis (2 15 - 1)) | 16 |
unsigned short | 0 bis 65.535 (0 bis 2 16 - 1) | 16 |
signed int | -32,767 bis 32,767 (- (2 15 - 1) bis (2 15 - 1)) | 16 |
unsigned int | 0 bis 65.535 (0 bis 2 16 - 1) | 16 |
signed long | -2147483647 bis 2.147.483.647 (- (Februar 31-01) bis (31-01 Februar)) | 32 |
unsigned long | 0 bis 4.294.967.295 (0 bis 2 32 - 1) | 32 |
Art | Mindestbereich | Minimale Bits erforderlich |
---|---|---|
signed long long | -9.223.372.036.854.775.807 zu 9,223,372,036,854,775,807 (- (2 63 - 1) bis (2 63 - 1)) | 64 |
unsigned long long | 0 bis 18.446.744.073.709.551.615 (0 bis 2 64 - 1) | 64 |
Da jeder Typ größer sein darf als seine Mindestgröße, können sich die Typen zwischen den Implementierungen unterscheiden. Das bemerkenswerteste Beispiel hierfür ist mit den 64-Bit - Datenmodellen LP64 und LLP64, wo LLP64 Systeme (wie 64-Bit - Windows) 32-Bit ints
und long
s und LP64 - Systeme (wie 64-Bit - Linux) haben 32-Bit - int
s und 64-Bit long
s. Daher kann für Integer-Typen nicht angenommen werden, dass sie auf allen Plattformen eine feste Breite haben.
Wenn ganzzahlige Typen mit fester Breite erforderlich sind, verwenden Sie Typen aus dem Header <cstdint>
Beachten Sie jedoch, dass der Standard es für Implementierungen optional macht, die Typen mit exakter Breite int8_t
, int16_t
, int32_t
, int64_t
, intptr_t
, uint8_t
, uint16_t
, uint32_t
, uint64_t
und uintptr_t
.
Größe von char16_t
und char32_t
Die Größen von char16_t
und char32_t
sind implementierungsdefiniert, wie in § 5.3.3.1 angegeben, mit den in § 3.9.1.5 angegebenen Bestimmungen:
char16_t
ist groß genug, um eine beliebige UTF-16-Codeeinheit darzustellen, und hat dieselbe Größe, Vorzeichen und Ausrichtung wieuint_least16_t
; es muss daher mindestens 16 Bit groß sein.char32_t
ist groß genug, um eine beliebige UTF-32-Codeeinheit darzustellen, und hat dieselbe Größe, Vorzeichen und Ausrichtung wieuint_least32_t
; es muss daher mindestens 32 Bit groß sein.
Größe des bool
Die Größe von bool
ist durch die Implementierung definiert und kann 1
sein oder nicht.
Größe von wchar_t
wchar_t
, wie in § 3.9.1.5 angegeben, ein eindeutiger Typ, dessen Wertebereich jede unterschiedliche Codeeinheit des größten erweiterten Zeichensatzes unter den unterstützten Gebietsschemas darstellen kann. Es hat die gleiche Größe, Vorzeichen und Ausrichtung wie ein anderer integraler Typ, der als zugrunde liegender Typ bezeichnet wird . Die Größe dieses Typs ist implementierungsdefiniert, wie in § 5.3.3.1 angegeben, und kann beispielsweise mindestens 8, 16 oder 32 Bit betragen. Wenn ein System Unicode unterstützt, muss wchar_t
beispielsweise mindestens 32 Bit umfassen (eine Ausnahme von dieser Regel ist Windows, wobei wchar_t
aus Kompatibilitätsgründen 16 Bit beträgt). Es ist vom Standard C90, ISO 9899: 1990 § 4.1.5, mit nur geringfügigen Umformungen vererbt.
Je nach Implementierung beträgt die Größe von wchar_t
oft, aber nicht immer 8, 16 oder 32 Bit. Die häufigsten Beispiele dafür sind:
- In Unix- und Unix-ähnlichen Systemen ist
wchar_t
32-Bit und wird normalerweise für UTF-32 verwendet. - In Windows ist
wchar_t
16-Bit und wird für UTF-16 verwendet. - Auf einem System, das nur 8-Bit-Unterstützung bietet, ist
wchar_t
8 Bit.
Wenn Unicode-Unterstützung gewünscht wird, wird empfohlen, char
für UTF-8, char16_t
für UTF-16 oder char32_t
für UTF-32 zu verwenden, anstatt wchar_t
.
Datenmodelle
Wie bereits erwähnt, können die Breiten von Integertypen zwischen Plattformen variieren. Die gebräuchlichsten Modelle sind folgende, wobei die Größen in Bits angegeben sind:
Modell | int | long | Zeiger |
---|---|---|---|
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 |
Von diesen Modellen:
- 16-Bit-Windows verwendete LP32.
- 32-Bit * Nix-Systeme (Unix, Linux, Mac OSX und andere Unix-ähnliche Betriebssysteme) und Windows verwenden ILP32.
- 64-Bit-Windows verwendet LLP64.
- 64-Bit * Nix-Systeme verwenden LP64.
Beachten Sie jedoch, dass diese Modelle im Standard selbst nicht ausdrücklich erwähnt werden.
Anzahl der Bits in einem Byte
In C ++ ist ein Byte der von einem char
Objekt belegte Platz. Die Anzahl der Bits in einem Byte wird durch CHAR_BIT
, das in climits
definiert climits
und mindestens 8 climits
muss. Während die meisten modernen Systeme 8-Bit-Bytes aufweisen und für POSIX CHAR_BIT
genau 8 ist, gibt es einige Systeme, bei denen CHAR_BIT
ist größer als 8, dh ein einzelnes Byte kann aus 8, 16, 32 oder 64 Bits bestehen.
Numerischer Wert eines Zeigers
Das Ergebnis des Umsetzens eines Zeigers auf eine Ganzzahl mit reinterpret_cast
ist implementierungsdefiniert, aber "... soll für diejenigen nicht überraschend sein, die die Adressierungsstruktur des zugrunde liegenden Computers 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
Ebenso ist der durch Konvertierung aus einer Ganzzahl erhaltene Zeiger implementierungsdefiniert.
uintptr_t
einen Zeiger als Ganzzahl zu speichern, verwenden Sie die Typen uintptr_t
oder 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 bezieht sich auf C99 für die Definition uintptr_t
(C99-Standard, 6.3.2.3):
ein vorzeichenloser Integer-Typ mit der Eigenschaft, dass ein beliebiger gültiger Zeiger auf
void
in diesen Typ konvertiert und dann wieder in einen Zeiger aufvoid
konvertiertvoid
kann und das Ergebnis dem ursprünglichen Zeiger entspricht.
Während für die meisten modernen Plattformen ein flacher Adressraum angenommen werden kann und die Arithmetik bei uintptr_t
der Arithmetik bei char *
, ist es durchaus möglich, dass eine Implementierung jede Transformation ausführt, wenn void *
in uintptr_t
, solange die Transformation dies kann Umkehrung beim uintptr_t
von uintptr_t
nach void *
.
Technische Aspekte
Bei XSI-konformen Systemen (X / Open System Interfaces) sind die Typen
intptr_t
unduintptr_t
erforderlich. Andernfalls sind sie optional .Funktionen im Sinne des C-Standards sind keine Objekte; Der C-Standard garantiert nicht, dass
uintptr_t
einen Funktionszeigeruintptr_t
kann. Die Konformität von POSIX (2.12.3) erfordert jedoch Folgendes:Alle Funktionszeigertypen müssen dieselbe Darstellung wie der Typzeiger auf void haben. Die Umwandlung eines Funktionszeigers in void * ändert nichts an der Darstellung. Ein void * -Wert, der sich aus einer solchen Konvertierung ergibt, kann mithilfe einer expliziten Umwandlung ohne Informationsverlust in den ursprünglichen Funktionszeigertyp konvertiert werden.
C99 §7.18.1:
Wenn Typedef-Namen definiert werden, die sich nur in Abwesenheit oder Vorhandensein des anfänglichen u unterscheiden, müssen sie entsprechend vorzeichenbehaftete und vorzeichenlose Typen angeben, wie in 6.2.5 beschrieben. Eine Implementierung, die einen dieser entsprechenden Typen bereitstellt, muss auch den anderen bereitstellen.
uintptr_t
kann sinnvoll sein, wenn Sie Dinge mit den Bits des Zeigers machen möchten, die Sie mit einer vorzeichenbehafteten Ganzzahl nicht so sinnvolluintptr_t
können.
Bereiche numerischer Typen
Die Bereiche der Integer-Typen sind implementierungsdefiniert. Der Header <limits>
enthält die Vorlage std::numeric_limits<T>
die die Minimal- und Maximalwerte aller grundlegenden Typen std::numeric_limits<T>
. Die Werte erfüllen die Garantien, die der C-Standard durch die <climits>
und (> = C ++ 11) <cinttypes>
.
-
std::numeric_limits<signed char>::min()
entsprichtSCHAR_MIN
, was kleiner oder gleich -127 ist. -
std::numeric_limits<signed char>::max()
entsprichtSCHAR_MAX
, der größer oder gleich 127 ist. -
std::numeric_limits<unsigned char>::max()
entsprichtUCHAR_MAX
, der größer als oder gleich 255 ist. -
std::numeric_limits<short>::min()
entsprichtSHRT_MIN
, was kleiner oder gleich -32767 ist. -
std::numeric_limits<short>::max()
entsprichtSHRT_MAX
, was größer oder gleich 32767 ist. -
std::numeric_limits<unsigned short>::max()
entsprichtUSHRT_MAX
, der größer als oder gleich 65535 ist. -
std::numeric_limits<int>::min()
entsprichtINT_MIN
, was kleiner oder gleich -32767 ist. -
std::numeric_limits<int>::max()
entsprichtINT_MAX
, der größer oder gleich 32767 ist. -
std::numeric_limits<unsigned int>::max()
entsprichtUINT_MAX
, der größer als oder gleich 65535 ist. -
std::numeric_limits<long>::min()
entsprichtLONG_MIN
, was gleich oder weniger als -2147483647 ist. -
std::numeric_limits<long>::max()
entsprichtLONG_MAX
, der größer oder gleich 2147483647 ist. -
std::numeric_limits<unsigned long>::max()
entsprichtULONG_MAX
, der größer als oder gleich 4294967295 ist.
-
std::numeric_limits<long long>::min()
entsprichtLLONG_MIN
, was kleiner oder gleich -9223372036854775807 ist. -
std::numeric_limits<long long>::max()
entsprichtLLONG_MAX
, der größer oder gleich 9223372036854775807 ist. -
std::numeric_limits<unsigned long long>::max()
entsprichtULLONG_MAX
, der größer oder gleich 18446744073709551615 ist.
Für Fließkommatypen T
ist max()
der maximale endliche Wert, während min()
der niedrigste positiv normalisierte Wert ist. Weitere Member werden für Gleitkommatypen bereitgestellt, die ebenfalls implementierungsdefiniert sind, jedoch bestimmte Garantien erfüllen, die der C-Standard durch den <cfloat>
-Header <cfloat>
.
- Das Mitglied
digits10
gibt die Anzahl der Nachkommastellen der Präzision.-
std::numeric_limits<float>::digits10
entsprichtFLT_DIG
, also mindestens 6. -
std::numeric_limits<double>::digits10
entsprichtDBL_DIG
, also mindestens 10. -
std::numeric_limits<long double>::digits10
entsprichtLDBL_DIG
, also mindestens 10.
-
- Das
min_exponent10
ist das minimale negative E, so dass 10 der Leistung E normal ist.-
std::numeric_limits<float>::min_exponent10
entsprichtFLT_MIN_10_EXP
, höchstens jedoch -37. -
std::numeric_limits<double>::min_exponent10
entsprichtDBL_MIN_10_EXP
, was höchstens -37 ist.std::numeric_limits<long double>::min_exponent10
entsprichtLDBL_MIN_10_EXP
, höchstens jedoch -37.
-
- Das
max_exponent10
ist das Maximum E, so dass 10 zur Potenz E endlich ist.-
std::numeric_limits<float>::max_exponent10
entsprichtFLT_MIN_10_EXP
, also mindestens 37. -
std::numeric_limits<double>::max_exponent10
entsprichtDBL_MIN_10_EXP
, also mindestens 37. -
std::numeric_limits<long double>::max_exponent10
entsprichtLDBL_MIN_10_EXP
, also mindestens 37.
-
- Wenn der Member
is_iec559
denis_iec559
true hat, entspricht der Typ der Norm IEC 559 / IEEE 754, und sein Bereich wird daher durch diese Norm festgelegt.
Wertdarstellung von Gleitkommatypen
Der Standard verlangt, dass long double
mindestens so viel Präzision bietet wie double
, was mindestens genauso viel Präzision wie float
bietet. Ein long double
kann einen beliebigen Wert darstellen, den ein double
kann, während ein double
einen beliebigen Wert darstellen kann, den ein float
kann. Die Details der Darstellung sind jedoch implementierungsdefiniert.
Bei einem Gleitkommatyp T
gibt std::numeric_limits<T>::radix
die von der Darstellung von T
verwendete std::numeric_limits<T>::radix
.
Wenn std::numeric_limits<T>::is_iec559
wahr ist, dann entspricht die Darstellung von T
einem der von IEC 559 / IEEE 754 definierten Formate.
Überlauf beim Konvertieren von Ganzzahl in vorzeichenbehaftete Ganzzahl
Wenn eine vorzeichenbehaftete oder vorzeichenlose Ganzzahl in einen vorzeichenbehafteten Ganzzahlentyp konvertiert wird und ihr Wert im Zieltyp nicht darstellbar ist, wird der erzeugte Wert durch die Implementierung definiert. Beispiel:
// 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)
Basiswert (und damit Größe) einer Aufzählung
Wenn der zugrunde liegende Typ nicht explizit für einen Aufzählungstyp mit nicht angegebenem Bereich angegeben ist, wird er in einer implementierungsdefinierten Weise bestimmt.
enum E {
RED,
GREEN,
BLUE,
};
using T = std::underlying_type<E>::type; // implementation-defined
Der Standard erfordert jedoch, dass der zugrunde liegende Typ einer Enumeration nicht größer als int
sei denn, int
und unsigned int
nicht alle Werte der Enumeration darstellen. Im obigen Code könnte T
also int
, unsigned int
oder short
, aber nicht long long
, um einige Beispiele zu geben.
Beachten Sie, dass eine Aufzählung dieselbe Größe (wie von sizeof
) wie ihr zugrunde liegender Typ hat.