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_tXSI (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 ) как его базовый тип.