C++
Поведение, определяемое реализацией
Поиск…
Char может быть неподписанным или подписанным
В стандарте не указывается, должен ли char
быть подписан или без знака. Различные компиляторы реализуют его по-другому или могут изменить его с помощью командной строки.
Размер интегральных типов
Следующие типы определяются как интегральные типы :
-
char
- Подписанные целые типы
- Беззнаковые целые типы
-
char16_t
иchar32_t
-
bool
-
wchar_t
За исключением sizeof(char)
/ sizeof(signed char)
/ sizeof(unsigned char)
, который разделен между § 3.9.1.1 [basic.fundamental / 1] и § 5.3.3.1 [expr.sizeof] и sizeof(bool)
, который полностью определяется реализацией и не имеет минимального размера, требования минимального размера этих типов приведены в разделе § 3.9.1 [basic.fundamental] стандарта и будут подробно описаны ниже.
Размер char
Все версии стандарта C ++ указывают в п. 5.3.3.1, что sizeof
дает 1
для unsigned char
, signed char
и char
(это реализация определяет, signed
ли тип char
или unsigned
).
char
достаточно большой, чтобы представлять 256 различных значений, чтобы быть пригодным для хранения кодовых блоков UTF-8.
Размер подписанных и неподписанных целых типов
Стандарт указывает в п. 3.9.1.2, что в списке стандартных стандартных целочисленных типов , состоящих из signed char
, short int
, int
, long int
и long long int
, каждый тип будет содержать как минимум столько же памяти, что и предыдущие это в списке. Кроме того, как указано в п. 3.9.1.3, каждый из этих типов имеет соответствующий стандартный беззнаковый целочисленный тип , unsigned char
, unsigned short int
, unsigned int
, unsigned long int
и unsigned long long int
, которые имеют одинаковый размер и выравнивание, как его соответствующий подписанный тип. Кроме того, как указано в п. 3.9.1.1, char
имеет те же требования к размеру и выравниванию, что и как signed char
и unsigned char
.
До C ++ 11 long long
и unsigned long long
официально не были частью стандарта C ++. Однако после их введения в C на C99 многие компиляторы поддерживали long long
расширенный целочисленный тип со unsigned long long
, а unsigned long long
как расширенный целочисленный тип без знака , с теми же правилами, что и типы C.
Таким образом, стандарт гарантирует, что:
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)
Конкретные минимальные размеры для каждого типа не указаны стандартом. Вместо этого каждый тип имеет минимальный диапазон значений, которые он может поддерживать, который, как указано в § 3.9.1.3, унаследован от стандарта C, в п. 5.2.4.2.1. Минимальный размер каждого типа может быть грубо выведен из этого диапазона, определяя минимальное количество требуемых бит; обратите внимание, что для любой данной платформы фактический поддерживаемый диапазон любого типа может быть больше минимального. Обратите внимание, что для подписанных типов диапазоны соответствуют своему дополнению, а не более часто используемому двум дополнениям; это позволяет более широкому диапазону платформ соответствовать стандарту.
Тип | Минимальный диапазон | Требуются минимальные бит |
---|---|---|
signed char | От -127 до 127 (- (от 2 7 до 1) до (2 7 - 1)) | 8 |
unsigned char | От 0 до 255 (от 0 до 2 8 - 1) | 8 |
signed short | -32,767 до 32,767 (- (2 15 - 1) до (2 15 - 1)) | 16 |
unsigned short | 0 до 65535 (от 0 до 2 16 - 1) | 16 |
signed int | -32,767 до 32,767 (- (2 15 - 1) до (2 15 - 1)) | 16 |
unsigned int | 0 до 65535 (от 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 до 32 - 1) | 32 |
Тип | Минимальный диапазон | Требуются минимальные бит |
---|---|---|
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 |
Поскольку каждому типу разрешено превышать требования к минимальному размеру, типы могут отличаться по размеру между реализациями. Наиболее примечательный пример этого - с 64-битными моделями данных LP64 и LLP64, где системы LLP64 (например, 64-разрядные Windows) имеют 32-битные ints
и long
s, а системы LP64 (например, 64-разрядные Linux) имеют 32-битный int
с и 64-разрядные long
с. Из-за этого нельзя считать, что целочисленные типы имеют фиксированную ширину на всех платформах.
Если требуются целые типы с фиксированной шириной, используйте типы из заголовка <cstdint>
, но обратите внимание, что стандарт делает его необязательным для реализаций для поддержки типов точной ширины int8_t
, int16_t
, int32_t
, int64_t
, intptr_t
, uint8_t
, uint16_t
, uint32_t
, uint64_t
и uintptr_t
.
Размер char16_t
и char32_t
Размеры char16_t
и char32_t
определяются реализацией, как указано в п. 5.3.3.1, с положениями, изложенными в п. 3.9.1.5:
char16_t
достаточно велик, чтобы представлять любой модуль кода UTF-16 и имеет тот же размер, подпись и выравнивание какuint_least16_t
; он должен иметь размер не менее 16 бит.char32_t
достаточно велик, чтобы представлять любой кодовый блок UTF-32 и имеет тот же размер, подпись и выравнивание какuint_least32_t
; он должен иметь размер не менее 32 бит.
Размер bool
Размер bool
определяется реализацией и может быть или не быть 1
.
Размер wchar_t
wchar_t
, как указано в п. 3.9.1.5, представляет собой отдельный тип, диапазон значений которого может представлять каждый отдельный блок кода самого большого расширенного набора символов среди поддерживаемых локалей. Он имеет тот же размер, подпись и выравнивание как один из других интегральных типов, который известен как его базовый тип . Размер этого типа определяется реализацией, как указано в п. 5.3.3.1, и может быть, например, не менее 8, 16 или 32 бит; если система поддерживает Unicode, например, wchar_t
требуется как минимум 32 бита (исключение из этого правила - Windows, где wchar_t
- 16 бит для целей совместимости). Он наследуется от стандарта C90, ISO 9899: 1990 § 4.1.5, с незначительной переписью.
В зависимости от реализации размер wchar_t
часто, но не всегда, 8, 16 или 32 бит. Наиболее распространенными примерами этого являются:
- В Unix и Unix-подобных системах
wchar_t
является 32-разрядным и обычно используется для UTF-32. - В Windows
wchar_t
является 16-разрядным и используется для UTF-16. - В системе, которая имеет только 8-битную поддержку,
wchar_t
имеет 8 бит.
Если требуется поддержка Unicode, рекомендуется использовать char
для UTF-8, char16_t
для UTF-16 или char32_t
для UTF-32 вместо использования wchar_t
.
Модели данных
Как упоминалось выше, ширина целых типов может различаться между платформами. Наиболее распространенными являются следующие модели с размерами, указанными в битах:
модель | int | long | указатель |
---|---|---|---|
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 |
Из этих моделей:
- 16-битная Windows использовала LP32.
- 32-битные * nix-системы (Unix, Linux, Mac OSX и другие Unix-подобные ОС) и Windows используют ILP32.
- 64-разрядная версия Windows использует LLP64.
- 64-битные * nix-системы используют LP64.
Обратите внимание, однако, что эти модели конкретно не упоминаются в самом стандарте.
Количество бит в байте
В C ++ байт - это пространство, занимаемое объектом char
. Количество бит в байте задается CHAR_BIT
, которое определяется в climits
и должно быть не менее 8. Хотя большинство современных систем имеют 8-битные байты, а POSIX требует, чтобы CHAR_BIT
был ровно 8, существуют некоторые системы, где CHAR_BIT
больше 8, т. е. один байт может состоять из 8, 16, 32 или 64 бит.
Числовое значение указателя
Результат литья указателя на целое число с использованием reinterpret_cast
определяется реализацией, но «... не может быть неудивительным для тех, кто знает структуру адресации лежащей в основе машины».
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
Аналогично, указатель, полученный преобразованием из целого числа, также определяется реализацией.
Правильный способ хранения указателя как целого - использовать uintptr_t
или 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 относится к C99 для определения uintptr_t
(стандарт C99, 6.3.2.3):
целочисленный тип без знака с тем свойством, что любой действительный указатель на
void
может быть преобразован в этот тип, а затем преобразован обратно в указатель наvoid
, и результат будет сравниваться с исходным указателем.
Хотя для большинства современных платформ вы можете принять плоское адресное пространство и что арифметика на uintptr_t
эквивалентна арифметике на char *
, вполне возможно, что реализация выполнит любое преобразование при литье void *
в uintptr_t
как только трансформация может быть отменено при отбрасывании от uintptr_t
до void *
.
Технические детали
В системах,
intptr_t
XSI (X / Open System Interfaces),uintptr_t
типыintptr_t
иuintptr_t
, в противном случае они являются необязательными .В значении стандарта C функции не являются объектами; в стандарте C не гарантируется, что
uintptr_t
может содержать указатель на функцию. В любом случае соответствие POSIX (2.12.3) требует:Все типы указателей функций должны иметь то же представление, что и указатель типа на void. Преобразование указателя функции в void * не должно изменять представление. Значение void *, возникающее в результате такого преобразования, может быть преобразовано обратно в исходный тип указателя функции с использованием явного приведения без потери информации.
C99 §7.18.1:
Когда определены имена typedef, отличающиеся только отсутствием или наличием начального u, они должны обозначать соответствующие типы подписей и без знака, как описано в 6.2.5; реализация, обеспечивающая один из этих соответствующих типов, также должна обеспечивать другую.
uintptr_t
может иметь смысл, если вы хотите сделать что-то с битами указателя, который вы не можете сделать так же разумно со знаком целого числа.
Диапазоны числовых типов
Диапазоны целочисленных типов определены реализацией. Заголовок <limits>
содержит шаблон std::numeric_limits<T>
который предоставляет минимальные и максимальные значения всех основных типов. Значения удовлетворяют гарантиям, предоставляемым стандартом C, через <climits>
и (> = C ++ 11) <cinttypes>
.
-
std::numeric_limits<signed char>::min()
равноSCHAR_MIN
, которое меньше или равно -127. -
std::numeric_limits<signed char>::max()
равноSCHAR_MAX
, которое больше или равно 127. -
std::numeric_limits<unsigned char>::max()
равноUCHAR_MAX
, который больше или равен 255. -
std::numeric_limits<short>::min()
равноSHRT_MIN
, которое меньше или равно -32767. -
std::numeric_limits<short>::max()
равноSHRT_MAX
, которое больше или равно 32767. -
std::numeric_limits<unsigned short>::max()
равноUSHRT_MAX
, который больше или равен 65535. -
std::numeric_limits<int>::min()
равноINT_MIN
, которое меньше или равно -32767. -
std::numeric_limits<int>::max()
равноINT_MAX
, которое больше или равно 32767. -
std::numeric_limits<unsigned int>::max()
равноUINT_MAX
, которое больше или равно 65535. -
std::numeric_limits<long>::min()
равноLONG_MIN
, которое меньше или равно -2147483647. -
std::numeric_limits<long>::max()
равноLONG_MAX
, которое больше или равно 2147483647. -
std::numeric_limits<unsigned long>::max()
равноULONG_MAX
, которое больше или равно 4294967295.
-
std::numeric_limits<long long>::min()
равноLLONG_MIN
, которое меньше или равно -9223372036854775807. -
std::numeric_limits<long long>::max()
равноLLONG_MAX
, который больше или равен 9223372036854775807. -
std::numeric_limits<unsigned long long>::max()
равноULLONG_MAX
, которое больше или равно 18446744073709551615.
Для типов с плавающей запятой T
max()
- максимальное конечное значение, а min()
- минимальное положительное нормированное значение. Дополнительные члены предоставляются для типов с плавающей точкой, которые также определены для реализации, но удовлетворяют определенным гарантиям, предоставляемым стандартом C, через заголовок <cfloat>
.
-
digits10
дают число десятичных цифр точности.-
std::numeric_limits<float>::digits10
равноFLT_DIG
, который не менее 6. -
std::numeric_limits<double>::digits10
равноDBL_DIG
, который не менее 10. -
std::numeric_limits<long double>::digits10
равноLDBL_DIG
, который не менее 10.
-
- Член
min_exponent10
является минимальным отрицательным E, так что 10 к мощности E является нормальным.-
std::numeric_limits<float>::min_exponent10
равноFLT_MIN_10_EXP
, что не более -37. -
std::numeric_limits<double>::min_exponent10
равноDBL_MIN_10_EXP
, что не более -37.std::numeric_limits<long double>::min_exponent10
равноLDBL_MIN_10_EXP
, что не более -37.
-
- Член
max_exponent10
- это максимум E такой, что 10 до степени E конечен.-
std::numeric_limits<float>::max_exponent10
равноFLT_MIN_10_EXP
, который не менее 37. -
std::numeric_limits<double>::max_exponent10
равноDBL_MIN_10_EXP
, который не менее 37. -
std::numeric_limits<long double>::max_exponent10
равноLDBL_MIN_10_EXP
, который составляет не менее 37.
-
- Если элемент
is_iec559
имеет значение true, тип соответствует IEC 559 / IEEE 754, и поэтому его диапазон определяется этим стандартом.
Представление значений типов с плавающей запятой
Стандарт требует, чтобы long double
обеспечивал как минимум такую же точность, как double
, которая обеспечивает как минимум такую же точность, как float
; и что long double
может представлять любое значение, которое может представлять double
, а double
может представлять любое значение, которое может представлять float
. Однако детали представления, однако, определены в реализации.
Для типа с плавающей точкой T
std::numeric_limits<T>::radix
указывает базовый знак, используемый представлением T
Если std::numeric_limits<T>::is_iec559
истинно, то представление T
соответствует одному из форматов, определенных IEC 559 / IEEE 754.
Переполнение при преобразовании из целого числа в целое число со знаком
Когда целое число под знаком или без знака преобразуется в целочисленный тип со знаком, а его значение не представляется в целевом типе, полученное значение определяется реализацией. Пример:
// 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)
Основной тип (и, следовательно, размер) перечисления
Если базовый тип явно не указан для типа нумерации без регистрации, он определяется определенным образом.
enum E {
RED,
GREEN,
BLUE,
};
using T = std::underlying_type<E>::type; // implementation-defined
Однако стандарт требует, чтобы базовый тип перечисления был не больше, чем int
если только int
и unsigned int
не могут представлять все значения перечисления. Поэтому в вышеприведенном коде T
может быть int
, unsigned int
или short
, но не long long
, чтобы дать несколько примеров.
Обратите внимание, что перечисление имеет тот же размер (который возвращается sizeof
) как его базовый тип.