Поиск…


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

C ++ 14

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

До 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)
C ++ 11
 <= 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
C ++ 11
Тип Минимальный диапазон Требуются минимальные бит
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 с. Из-за этого нельзя считать, что целочисленные типы имеют фиксированную ширину на всех платформах.

C ++ 11

Если требуются целые типы с фиксированной шириной, используйте типы из заголовка <cstdint> , но обратите внимание, что стандарт делает его необязательным для реализаций для поддержки типов точной ширины int8_t , int16_t , int32_t , int64_t , intptr_t , uint8_t , uint16_t , uint32_t , uint64_t и uintptr_t .

C ++ 11

Размер 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 бит.
C ++ 11

Если требуется поддержка 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;
C ++ 11
// 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.
C ++ 11
  • 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 ) как его базовый тип.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow