【问题标题】:Why is numeric_limits<uint16_t>::max() not equal to -1?为什么 numeric_limits<uint16_t>::max() 不等于 -1?
【发布时间】:2023-03-20 14:36:01
【问题描述】:
#include <iostream>
#include <cstdint>

using namespace std;

static_assert(-1 == numeric_limits<uint64_t>::max()); // ok
static_assert(-1 == numeric_limits<uint32_t>::max()); // ok
static_assert(-1 == numeric_limits<uint16_t>::max()); // error

int main()
{
    cout << numeric_limits<uint16_t>::max() << endl;
    cout << uint16_t(-1) << endl;
}

输出:

65535
65535

为什么numeric_limits&lt;uint16_t&gt;::max()不等于-1?

更新:

根据cppref

同样,USHRT_MAX 可能不是无符号类型:它的类型可能是 诠释。

【问题讨论】:

  • “may be int”和“is int”是两个截然不同的东西
  • 您能否详细解释一下为什么您认为它应该等于-1?当我们不知道它是什么时,很难消除误解!
  • 对我来说,-1 表示 0xFFFF....,所以对于无符号整数,它应该等于该整数类型的最大值。
  • 好的。好吧,-1 并不意味着 0xFFFF。这意味着-1。听起来您将 C++ 视为内存中的原始编程位。不是。
  • @xmllmx 请注意我的答案的附录,关于平台特定/依赖的行为。

标签: c++ standards numeric unsigned-integer compile-time-constant


【解决方案1】:

整数转换和促销

uint16_t 值经过整数提升,而对于(您的特定平台;见下文)uint32_tuint64_t 情况下-1 (本身不是整数文字,而是应用于整数文字1 的一元减号运算符),通过整数转换,结果值等于@ 的最大相应值987654336@ 和 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()

来自[expr.eq]/1[expr.eq]/6 [强调我的]:

[expr.eq]/1

==(等于)和!=(不等于)运算符组 左到右。操作数应具有算术、枚举、 指针,或指向成员类型的指针,或类型std​::​nullptr_­t。这 运算符==!= 都产生truefalse,即结果 bool 类型。在以下每种情况下,操作数应具有相同的 在应用了指定的转换后键入

[expr.eq]/6

如果两个操作数都是算术**或枚举类型,则通常的算术转换对两个操作数进行;每个 如果指定的关系是,运算符应产生true truefalse 如果是 false

来自[conv.integral]/1[conv.integral]/2

[conv.integral]/1

整数类型的纯右值可以转换为另一种整数类型的纯右值。非作用域枚举类型的纯右值可以转换为整数类型的纯右值。

[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[强调我的]:

[conv.prom]/1

boolchar16_­tchar32_­twchar_­t以外的整数类型的纯右值其整数转换等级小于int的等级可以转换为type int 如果int 可以表示源类型的所有值;否则,可以将源纯右值转换为unsigned int 类型的纯右值。


平台相关行为

然而,虽然由于unsigned short int 的最大值下限要求,我们能够为上面的uint16_t 提出论据——保证uint16_t 的整数转换等级总是低于 int — 我们不能提出相反的论点,因为uint32_t永远不会低于整数转换等级 int,因为 ISO C++ 标准对基本整数类型的最大值没有上限要求。

来自[basic.fundamental]/2[basic.fundamental]/3 [摘录,强调我的]:

[basic.fundamental]/2

有五种标准有符号整数类型:“signed char”, “short int”、“int”、“long int”和“long long int”。在这个 列表,每种类型提供的存储空间至少与前面的相同 它在列表中。 [...] 普通 ints 有建议的自然尺寸 通过执行环境的架构;另一个签名 提供整数类型以满足特殊需求。

[basic.fundamental]/3

对于每个标准的有符号整数类型,都存在一个 对应的(但不同的)标准无符号整数类型: “unsigned char”、“unsigned short int”、“unsigned int”、 “unsigned long int”和“unsigned long long int”,每个 占用相同的存储量并具有相同的对齐方式 要求为对应的有符号整数类型; [...]

有符号和无符号整数类型应满足约束 在 C 标准第 5.2.4.2.1 节中给出

并且,来自C11 Standard draft [摘录,强调我的]:

5.2.4.2.1 整数类型的大小&lt;limits.h&gt;

[...] 它们的实现定义的值应等于或大于 幅度(绝对值)与所示的相同,符号相同。

[...]

  • short int 类型对象的最大值:SHRT_MAX +32767

  • int 类型对象的最大值:INT_MAX +32767

[...]

请注意,这些最大值描述了最大值的下限,相应的基本整数类型应该能够存储,而对这些最大值的上限。此外,从上面的 [basic.fundamental]/2 引用中回想一下,每个后续的基本(有符号)整数类型只需要提供 至少 与处理它的那个(在列表中)一样多的存储空间。

这意味着,理论上,一个平台可以将 short intint 分别实现为 32 位宽和 64 位宽的整数,这意味着,在这个平台上,uint32_t 将具有与(unsigned) short int,这意味着比int低于的转化排名,在这种情况下,[conv.prom]/1 也适用于这个特定平台上的uint32_t 示例 .

【讨论】:

    【解决方案2】:

    因为-1 没有转换为uint16_t

    std::numeric_limits&lt;std::uint16_t&gt;::max() 被提升为 int-1 != 65535

    【讨论】:

      猜你喜欢
      • 2012-12-01
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-12
      • 2011-02-15
      • 1970-01-01
      • 2021-04-02
      相关资源
      最近更新 更多