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 i char32_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 ).

C ++ 14

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 .

C ++ 11

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)
C ++ 11
 <= 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
C ++ 11
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.

C ++ 11

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 .

C ++ 11

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 jak uint_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 jak uint_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.
C ++ 11

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;
C ++ 11
// 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 i uintptr_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ówny SCHAR_MIN , który jest mniejszy lub równy -127.
  • std::numeric_limits<signed char>::max() jest równy SCHAR_MAX , który jest większy lub równy 127.
  • std::numeric_limits<unsigned char>::max() jest równe UCHAR_MAX , który jest większy lub równy 255.
  • std::numeric_limits<short>::min() jest równy SHRT_MIN , który jest mniejszy lub równy -32767.
  • std::numeric_limits<short>::max() jest równy SHRT_MAX , który jest większy lub równy 32767.
  • std::numeric_limits<unsigned short>::max() jest równe USHRT_MAX , który jest większy lub równy 65535.
  • std::numeric_limits<int>::min() jest równe INT_MIN , który jest mniejszy lub równy -32767.
  • std::numeric_limits<int>::max() jest równe INT_MAX , który jest większy lub równy 32767.
  • std::numeric_limits<unsigned int>::max() jest równe UINT_MAX , który jest większy lub równy 65535.
  • std::numeric_limits<long>::min() jest równe LONG_MIN , który jest mniejszy lub równy -2147483647.
  • std::numeric_limits<long>::max() jest równe LONG_MAX , który jest większy lub równy 2147483647.
  • std::numeric_limits<unsigned long>::max() jest równe ULONG_MAX , który jest większy lub równy 4294967295.
C ++ 11
  • std::numeric_limits<long long>::min() jest równe LLONG_MIN , który jest mniejszy lub równy -9223372036854775807.
  • std::numeric_limits<long long>::max() jest równe LLONG_MAX , który jest większy lub równy 9223372036854775807.
  • std::numeric_limits<unsigned long long>::max() jest równe ULLONG_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.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow