C++
Zachowanie zdefiniowane w implementacji
Szukaj…
Char może być niepodpisany lub podpisany
Standard nie określa, czy char
powinien być podpisany, czy niepodpisany. Różne kompilatory implementują go inaczej lub mogą pozwolić na zmianę za pomocą przełącznika wiersza poleceń.
Rozmiar typów całkowych
Następujące typy są zdefiniowane jako typy integralne :
-
char
- Podpisane typy liczb całkowitych
- Niepodpisane typy liczb całkowitych
-
char16_t
ichar32_t
-
bool
-
wchar_t
Z wyjątkiem sizeof(char)
/ sizeof(signed char)
/ sizeof(unsigned char)
, który jest podzielony między § 3.9.1.1 [basic.fundamental / 1] i § 5.3.3.1 [expr.sizeof], i sizeof(bool)
, który jest całkowicie zdefiniowany w ramach implementacji i nie ma minimalnego rozmiaru, wymagania dotyczące minimalnego rozmiaru tych typów podano w sekcji 3.9.1 [podstawowy. podstawowy] normy i należy je wyszczególnić poniżej.
Rozmiar char
Wszystkie wersje standardu C ++ określają w § 5.3.3.1, że sizeof
daje 1
dla unsigned char
, signed char
i char
(jest to implementacja zdefiniowana, czy typ char
jest signed
czy unsigned
).
char
jest wystarczająco duży, aby reprezentować 256 różnych wartości, aby był odpowiedni do przechowywania jednostek kodu UTF-8.
Rozmiar typów całkowitych ze znakiem i bez znaku
Norma określa w § 3.9.1.2, że na liście standardowych typów liczb całkowitych ze znakiem , składających się ze signed char
, short int
, int
, long int
i long long int
, każdy typ zapewni co najmniej tyle samo miejsca co poprzednie to na liście. Ponadto, jak określono w § 3.9.1.3, każdy z tych typów ma odpowiadający standardowy typ liczby całkowitej unsigned char
, unsigned short int
unsigned char
, unsigned short int
, unsigned int
, unsigned long int
i unsigned long long int
, który ma taki sam rozmiar i wyrównanie jak odpowiadający mu podpisany typ. Dodatkowo, jak określono w § 3.9.1.1, char
ma taki sam rozmiar i wymagania wyrównania, jak signed char
i unsigned char
.
Przed wersją C ++ 11 long long
i unsigned long long
nie były oficjalnie częścią standardu C ++. Jednak po ich wprowadzeniu do C, w C99, wiele kompilatorów obsługiwało long long
jako rozszerzony typ liczb całkowitych i unsigned long long
jako rozszerzony typ liczb całkowitych , z tymi samymi regułami co typy C.
Standard gwarantuje zatem, że:
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)
Określone minimalne rozmiary dla każdego typu nie są podane przez standard. Zamiast tego każdy typ ma minimalny zakres wartości, które może obsłużyć, co, jak określono w § 3.9.1.3, odziedziczone ze standardu C, w § 5.2.2.2.1. Minimalny rozmiar każdego typu można z grubsza wywnioskować z tego zakresu, określając minimalną liczbę wymaganych bitów; należy pamiętać, że dla dowolnej platformy rzeczywisty obsługiwany zakres dowolnego typu może być większy niż minimum. Zauważ, że dla typów ze znakiem zakresy odpowiadają uzupełnieniu jednego, a nie najczęściej używanemu uzupełnieniu dwóch; Ma to na celu umożliwienie szerszego zakresu platform zgodnych ze standardem.
Rodzaj | Minimalny zasięg | Wymagane minimum bitów |
---|---|---|
signed char | -127 do 127 (- (2 7 - 1) do (2 7 - 1)) | 8 |
unsigned char | Od 0 do 255 (od 0 do 2 8-1 ) | 8 |
signed short | -32767 do 32767 (- (2 15 - 1) do (2, 15 - 1)) | 16 |
unsigned short | 0 do 65535 (od 0 do 2 16 - 1) | 16 |
signed int | -32767 do 32767 (- (2 15 - 1) do (2, 15 - 1)) | 16 |
unsigned int | 0 do 65535 (od 0 do 2 16 - 1) | 16 |
signed long | -2147483647 do 2147483647 (- (2 31 - 1) do (2, 31 - 1)) | 32 |
unsigned long | Od 0 do 4 294 967 295 (od 0 do 2 32-1 ) | 32 |
Rodzaj | Minimalny zasięg | Wymagane minimum bitów |
---|---|---|
signed long long | -9,223,372,036,854,775,807 do 9 223,372,036,854,775,807 (- (2 63 - 1) do (2 63 - 1)) | 64 |
unsigned long long | 0 do 18,446,744,073,709,551,615 (0 do 2 64 - 1) | 64 |
Ponieważ każdy typ może być większy niż wymagany minimalny rozmiar, typy mogą różnić się rozmiarem między implementacjami. Najbardziej godnym uwagi przykładem jest 64-bitowe modele danych LP64 i LLP64, w których systemy LLP64 (takie jak 64-bitowy system Windows) mają 32-bitowe wartości ints
i long
s, a systemy LP64 (takie jak 64-bitowy system Linux) mają 32-bitowy int
s i 64-bitowej long
s. Z tego powodu nie można zakładać, że typy liczb całkowitych mają stałą szerokość na wszystkich platformach.
Jeśli wymagane są typy całkowite o stałej szerokości, użyj typów z nagłówka <cstdint>
, ale zauważ, że standard umożliwia opcjonalne implementacje do obsługi typów o dokładnej szerokości int8_t
, int16_t
, int32_t
, int64_t
, intptr_t
, uint8_t
, uint16_t
, uint32_t
, uint64_t
i uintptr_t
.
Rozmiar char16_t
i char32_t
Rozmiary char16_t
i char32_t
są zdefiniowane jako implementacja, jak określono w § 5.3.3.1, z zastrzeżeniem podanym w § 3.9.1.5:
char16_t
jest wystarczająco duży, aby reprezentować dowolną jednostkę kodu UTF-16, i ma ten sam rozmiar, podpis i wyrównanie jakuint_least16_t
; dlatego wymagana jest wielkość co najmniej 16 bitów.char32_t
jest wystarczająco duży, aby reprezentować dowolną jednostkę kodu UTF-32, i ma ten sam rozmiar, podpis i wyrównanie jakuint_least32_t
; dlatego wymagana jest wielkość co najmniej 32 bity.
Rozmiar bool
Rozmiar bool
jest zdefiniowany w implementacji i może, ale nie musi, wynosić 1
.
Rozmiar wchar_t
wchar_t
, jak określono w § 3.9.1.5, jest odrębnym typem, którego zakres wartości może reprezentować każdą odrębną jednostkę kodową największego rozszerzonego zestawu znaków wśród obsługiwanych ustawień narodowych. Ma ten sam rozmiar, sygnaturę i wyrównanie, co jeden z innych typów integralnych, znany jako typ podstawowy . Rozmiar tego typu jest zdefiniowany w implementacji, jak określono w § 5.3.3.1, i może na przykład wynosić co najmniej 8, 16 lub 32 bity; jeśli system obsługuje na przykład Unicode, na przykład wchar_t
musi mieć co najmniej 32 bity (wyjątek od tej reguły to Windows, gdzie wchar_t
to 16 bitów dla celów kompatybilności). Jest dziedziczony ze standardu C90, ISO 9899: 1990 § 4.1.5, z niewielkim przeredagowaniem.
W zależności od implementacji rozmiar wchar_t
wynosi często, ale nie zawsze, 8, 16 lub 32 bity. Najczęstsze ich przykłady to:
- W systemach uniksowych i uniksowych
wchar_t
jest 32-bitowy i zwykle jest używany w UTF-32. - W Windows
wchar_t
jest 16-bitowy i jest używany w UTF-16. - W systemie, który obsługuje tylko 8 bitów,
wchar_t
to 8 bitów.
Jeśli pożądana jest obsługa Unicode, zaleca się użycie char
dla UTF-8, char16_t
dla UTF-16 lub char32_t
dla UTF-32 zamiast wchar_t
.
Modele danych
Jak wspomniano powyżej, szerokości typów całkowitych mogą się różnić między platformami. Najpopularniejsze modele są następujące, z rozmiarami określonymi w bitach:
Model | int | long | wskaźnik |
---|---|---|---|
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 |
Z tych modeli:
- 16-bitowy system Windows używał LP32.
- Systemy 32-bitowe * nix (Unix, Linux, Mac OSX i inne systemy uniksopodobne) i Windows używają ILP32.
- 64-bitowy system Windows korzysta z LLP64.
- Systemy 64-bitowe * nix używają LP64.
Należy jednak pamiętać, że modele te nie są specjalnie wymienione w samym standardzie.
Liczba bitów w bajcie
W C ++ bajt to przestrzeń zajmowana przez obiekt char
. Liczba bitów w bajcie jest określona przez CHAR_BIT
, który jest zdefiniowany w climits
i musi wynosić co najmniej 8. Podczas gdy większość współczesnych systemów ma 8-bitowych bajtów, a POSIX wymaga, aby CHAR_BIT
dokładnie 8, istnieją systemy, w których CHAR_BIT
jest większy niż 8, tj. pojedynczy bajt może składać się z 8, 16, 32 lub 64 bitów.
Wartość liczbowa wskaźnika
Wynik rzutowania wskaźnika na liczbę całkowitą za pomocą reinterpret_cast
jest zdefiniowany w implementacji, ale „... ma być zaskakujący dla tych, którzy znają strukturę adresowania komputera bazowego”.
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
Podobnie wskaźnik uzyskany przez konwersję z liczby całkowitej jest również zdefiniowany w implementacji.
Właściwym sposobem przechowywania wskaźnika jako liczby całkowitej jest użycie typów uintptr_t
lub 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 odnosi się do C99 dla definicji uintptr_t
(standard C99, 6.3.2.3):
typ całkowity bez znaku z właściwością, że dowolny prawidłowy wskaźnik na wartość
void
można przekonwertować na ten typ, a następnie przekonwertować z powrotem na wskaźnik na wartośćvoid
, a wynik porówna się z pierwotnym wskaźnikiem.
Chociaż dla większości współczesnych platform można założyć płaską przestrzeń adresową, a arytmetyka na uintptr_t
jest równoważna arytmetyki na char *
, jest całkiem możliwe, że implementacja wykona dowolną transformację podczas rzucania void *
na uintptr_t
o ile transformacja może być odwrócony podczas rzutowania z uintptr_t
na void *
.
Techniczne
W systemach zgodnych z XSI (X / Open System Interfaces) wymagane są typy
intptr_t
iuintptr_t
, w przeciwnym razie są one opcjonalne .W rozumieniu standardu C funkcje nie są obiektami; standard C nie gwarantuje, że
uintptr_t
może przechowywać wskaźnik funkcji. W każdym razie zgodność z POSIX (2.12.3) wymaga:Wszystkie typy wskaźników funkcji powinny mieć taką samą reprezentację jak wskaźnik typu, który ma zostać unieważniony. Konwersja wskaźnika funkcji na void * nie zmienia reprezentacji. Wartość void * wynikająca z takiej konwersji może zostać przekonwertowana z powrotem na pierwotny typ wskaźnika funkcji, przy użyciu jawnego rzutowania, bez utraty informacji.
C99 §7.18.1:
Gdy zdefiniowane są nazwy maszynowe różniące się tylko brakiem lub obecnością początkowego u, będą one oznaczać odpowiadające im typy podpisane i niepodpisane, jak opisano w 6.2.5; implementacja zapewniająca jeden z tych odpowiednich typów zapewnia również drugi.
uintptr_t
może mieć sens, jeśli chcesz zrobić coś z bitami wskaźnika, czego nie możesz zrobić tak rozsądnie z podpisaną liczbą całkowitą.
Zakresy typów numerycznych
Zakresy typów całkowitych są zdefiniowane w implementacji. Nagłówek <limits>
udostępnia std::numeric_limits<T>
który zapewnia minimalne i maksymalne wartości wszystkich podstawowych typów. Wartości spełniają gwarancje zapewniane przez standard C za pomocą <climits>
i (> = C ++ 11) <cinttypes>
.
-
std::numeric_limits<signed char>::min()
jest równySCHAR_MIN
, który jest mniejszy lub równy -127. -
std::numeric_limits<signed char>::max()
jest równySCHAR_MAX
, który jest większy lub równy 127. -
std::numeric_limits<unsigned char>::max()
jest równeUCHAR_MAX
, który jest większy lub równy 255. -
std::numeric_limits<short>::min()
jest równySHRT_MIN
, który jest mniejszy lub równy -32767. -
std::numeric_limits<short>::max()
jest równySHRT_MAX
, który jest większy lub równy 32767. -
std::numeric_limits<unsigned short>::max()
jest równeUSHRT_MAX
, który jest większy lub równy 65535. -
std::numeric_limits<int>::min()
jest równeINT_MIN
, który jest mniejszy lub równy -32767. -
std::numeric_limits<int>::max()
jest równeINT_MAX
, który jest większy lub równy 32767. -
std::numeric_limits<unsigned int>::max()
jest równeUINT_MAX
, który jest większy lub równy 65535. -
std::numeric_limits<long>::min()
jest równeLONG_MIN
, który jest mniejszy lub równy -2147483647. -
std::numeric_limits<long>::max()
jest równeLONG_MAX
, który jest większy lub równy 2147483647. -
std::numeric_limits<unsigned long>::max()
jest równeULONG_MAX
, który jest większy lub równy 4294967295.
-
std::numeric_limits<long long>::min()
jest równeLLONG_MIN
, który jest mniejszy lub równy -9223372036854775807. -
std::numeric_limits<long long>::max()
jest równeLLONG_MAX
, który jest większy lub równy 9223372036854775807. -
std::numeric_limits<unsigned long long>::max()
jest równeULLONG_MAX
, który jest większy lub równy 18446744073709551615.
Dla typów zmiennoprzecinkowych T
, max()
jest maksymalną wartością skończoną, podczas gdy min()
jest minimalną dodatnią znormalizowaną wartością. Dodatkowe typy są przewidziane dla typów zmiennoprzecinkowych, które są również zdefiniowane w implementacji, ale spełniają pewne gwarancje zapewniane przez standard C przez nagłówek <cfloat>
.
-
digits10
liczbę cyfr dziesiętnych dokładności.-
std::numeric_limits<float>::digits10
równa sięFLT_DIG
, co najmniej 6. -
std::numeric_limits<double>::digits10
równa sięDBL_DIG
, co najmniej 10. -
std::numeric_limits<long double>::digits10
równa sięLDBL_DIG
, co najmniej 10.
-
- Element
min_exponent10
jest minimalnym ujemnym E takim, że 10 do potęgi E jest normalne.-
std::numeric_limits<float>::min_exponent10
równa sięFLT_MIN_10_EXP
, co najwyżej -37. -
std::numeric_limits<double>::min_exponent10
równa sięDBL_MIN_10_EXP
, co najwyżej -37.std::numeric_limits<long double>::min_exponent10
równa sięLDBL_MIN_10_EXP
, co najwyżej -37.
-
- Element
max_exponent10
jest maksymalnym E takim, że 10 do potęgi E jest skończone.-
std::numeric_limits<float>::max_exponent10
równa sięFLT_MIN_10_EXP
, co najmniej 37. -
std::numeric_limits<double>::max_exponent10
równa sięDBL_MIN_10_EXP
, co najmniej 37. -
std::numeric_limits<long double>::max_exponent10
równa sięLDBL_MIN_10_EXP
, co najmniej 37.
-
- Jeśli element
is_iec559
ma wartość true, typ jest zgodny z IEC 559 / IEEE 754, a zatem jego zasięg jest określony przez tę normę.
Reprezentacja wartości typów zmiennoprzecinkowych
Norma wymaga, aby long double
zapewniał co najmniej tyle samo precyzji co double
, co zapewnia co najmniej tyle samo precyzji co liczba float
; i że long double
może reprezentować dowolną wartość, którą double
może reprezentować, podczas gdy double
może reprezentować dowolną wartość, którą może reprezentować float
. Szczegóły reprezentacji są jednak zdefiniowane w implementacji.
Dla zmiennoprzecinkowego typu T
, std::numeric_limits<T>::radix
określa podstawę używaną przez reprezentację T
Jeśli std::numeric_limits<T>::is_iec559
jest prawdą, wówczas reprezentacja T
pasuje do jednego z formatów zdefiniowanych w IEC 559 / IEEE 754.
Przepełnienie podczas konwersji z liczby całkowitej na liczbę całkowitą ze znakiem
Gdy albo liczba całkowita ze znakiem, albo bez znaku jest konwertowana na typ liczby całkowitej ze znakiem, a jego wartość nie jest reprezentowalna w typie docelowym, wytwarzana wartość jest definiowana implementacyjnie. Przykład:
// 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)
Typ bazowy (a zatem i rozmiar) wyliczenia
Jeśli typ bazowy nie jest jawnie określony dla nieokreślonego typu wyliczenia, jest on określany w sposób zdefiniowany w implementacji.
enum E {
RED,
GREEN,
BLUE,
};
using T = std::underlying_type<E>::type; // implementation-defined
Jednak standard wymaga, aby podstawowy typ wyliczenia nie był większy niż int
chyba że zarówno int
jak i unsigned int
nie są w stanie reprezentować wszystkich wartości wyliczenia. Dlatego w powyższym kodzie T
może być int
, unsigned int
lub short
, ale nie long long
, aby podać kilka przykładów.
Zauważ, że wyliczenie ma taki sam rozmiar (zwracany przez sizeof
) jak jego typ bazowy.