Целочисленные конверсии и продвижения
Значение uint16_t
проходит через целочисленное продвижение , тогда как для (вашей конкретной платформы; см. Ниже) случаи uint32_t
и uint64_t
имеют значение -1
значение (само по себе не целочисленный литерал, а унарный минус, примененный к целочисленному литералу 1
), проходит через целочисленное преобразование с результирующим значением, равным максимальное соответствующее значение типов uint32_t
и uint64_t
из-за целочисленной конгруэнции между исходным и целевым значениями этого преобразования.
static_assert(-1 == std::numeric_limits<std::uint64_t>::max());
// ^^
// | Integer conversion:
// | Destination type: uint64_t
// | Resulting value: std::numeric_limits<std::uint64_t>::max()
static_assert(-1 == std::numeric_limits<std::uint32_t>::max());
// ^^
// | Integer conversion:
// | Destination type: uint32_t
// | Resulting value: std::numeric_limits<std::uint32_t>::max()
static_assert(-1 == std::numeric_limits<std::uint16_t>::max());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// | Integer promotion:
// | Destination type: int
// | Resulting value: std::numeric_limits<std::uint16_t>::max()
С [конв. целое] / 1 и [conv.integral] / 2 :
[conv.integral] / 1
Prvalue целочисленного типа может быть преобразовано в значение другого целочисленного типа. Значение типа нумерации с незаданной областью может быть преобразовано в значение типа целого числа.
[conv.integral] / 2
Если тип назначения не имеет знака, полученное значение будет наименьшим целое число без знака соответствует исходному целому числу (по модулю 2n
, где n
- количество битов, используемых для представления типа без знака). [Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). - конец примечания]
Одно это должно привести к одинаковому поведению для всех ваших трех примеров. Однако для случая uint16_t
отличается то, что применяется [conv.integral] / 5 :
[conv.integral] / 5
преобразования, разрешенные как интегральные продвижения, исключаются из набора интегральных преобразований.
С [conv.rank] / 1
[conv.rank ] / 1
Каждый целочисленный тип имеет ранг целочисленного преобразования, определяемый следующим образом:
[...]
(1.3) Ранг long long int
должен быть больше чем ранг long
int
, который должен быть больше ранг int
, который должен превышать ранг short int
, который должен превышать ранг signed char
.
(1.4) Ранг любого целого типа без знака должен равняться рангу соответствующего целочисленного типа со знаком.
ранг целочисленного преобразования uint16_t
(такой же ранг или ниже, чем short int
) ниже, чем int
, что означает, что [conv.prom] / 1 применяется для uint16_t
[ выделение шахта]:
* 10 82 * [conv.prom] / 1
Prvalue целочисленного типа, отличного от bool
, char16_t
, char32_t
или wchar_t
, чей ранг целочисленного преобразования меньше, чем ранг int
может быть преобразован в prvalue типа int
, если int
может представлять все значения типа источника; в противном случае исходное значение может быть преобразовано в значение типа unsigned int
.
Поведение, зависящее от платформы
Однако , хотя мы смогли аргумент для uint16_t
выше из-за требования нижней границы для максимального значения unsigned short int
- гарантируя, что uint16_t
всегда имеет более низкий целочисленный рейтинг конверсии, чем int
- мы не можем приведите обратный аргумент для того факта, что uint32_t
не будет никогда не будет иметь ниже целочисленного ранга преобразования , чем int
, так как стандарт ISO C ++ не устанавливает верхних границ на максимуме значение требование к основным целочисленным типам.
С [basi c .fundamental] / 2 и [basi c .fundamental] / 3 [извлечение, выделение мое]:
[basi c .fundamental] / 2
Существует пять стандартных целочисленных типов со знаком: «signed char
»,« short int
»,« int
»,« long int
»и« long long int
». В этом списке каждый тип обеспечивает как минимум столько же памяти, сколько предшествует ему в списке . [...] Простые int
s имеют естественный размер, предложенный архитектурой среды исполнения ; другие целочисленные типы со знаком предоставляются для удовлетворения особых потребностей.
[basi c .fundamental] / 3
Для каждого из стандартных целочисленных типов со знаком существует соответствующий (но различный) стандартный целочисленный тип без знака: «unsigned char
», «* 1145» * »,« unsigned int
»,« unsigned long int
»и« unsigned long long int
», каждый из которых занимает тот же объем памяти и имеет те же требования к выравниванию, что и соответствующий целочисленный тип со знаком; [...]
Целочисленные типы со знаком и без знака должны удовлетворять ограничениям, указанным в стандарте C, раздел 5.2.4.2.1 .
И из C11 Стандартного черновика [извлечение, выделение шахта]:
5.2.4.2.1 Размеры целочисленных типов <limits.h>
[...] Их определяемые реализацией значения должны быть равными или большими по величине (абсолютное значение) показанным с тем же знаком.
[... ]
[...]
Обратите внимание, что эти максимальные значения описывают нижнюю границу максимума значения , которые должен хранить соответствующий основной целочисленный тип, тогда как в верхней границе этих максимальных значений нет требования. Кроме того, напомним из цитаты [basi c .fundamental] / 2 выше, что каждому последующему фундаментальному (подписанному) целочисленному типу требуется только по крайней мере столько же памяти, сколько и тому, который его обрабатывает (в списке) ,
Это означает, что теоретически платформа может реализовывать short int
и int
как 32-битные и 64-битные целые числа соответственно, а это означает, что на этой платформе uint32_t
будет иметь одно и то же целое число конверсионный ранг как (unsigned
) short int
, что будет означать более низкий конверсионный ранг, чем int
, и в этом случае [conv.prom]/1
будет применяться также для uint32_t
примера для этого конкретная платформа .