【问题标题】:Will unique values in uint64_t also be unique in int64_tuint64_t 中的唯一值在 int64_t 中是否也是唯一的
【发布时间】:2019-10-03 01:32:12
【问题描述】:

给定一个唯一的 (std::uint64_t 类型) 整数向量,如果我将 (std::uint64_t 类型) 向量转换为 (std::int64_t 类型) 整数向量,它会保证唯一吗?

像这样投射

std::vector<std::uint64_t> unsignedVec;
std::vector<std::int64_t> signedVec( unsignedVec.begin(), unsignedVec.end() );

【问题讨论】:

  • 生成、投射是什么意思?
  • 也许吧。你将如何生成std::int64_t 的向量?
  • “生成”是什么意思?如果您的意思是“强制转换”,则您的原始整数将小于或等于 int64 可表示的最大值(在这种情况下与原始 uint64_t 数字相同),或者您的程序将表现出未定义的行为,并且任何事情都可能发生.
  • @SergeyA 将无符号类型转换为有符号类型不是未定义的行为。溢出的有符号整数是,而不是强制转换。
  • @Resurrection 将积分转换为无法表示的范围是未定义的,这正是我所说的。

标签: c++ c++11 language-lawyer


【解决方案1】:

会保证唯一吗?

形式上它是由实现定义的,但在任何合理的平台上它都应该是唯一的。

(特别是如果提供了int64_thas to be 2 的补码。)

自 C++20 以来,它必须是唯一的。


https://en.cppreference.com/w/cpp/language/implicit_conversion#Numeric_conversions

如果目标类型是有符号的,如果源整数可以在目标类型中表示,则值不会改变。 [否则结果是实现定义的(C++20 前)] [目标类型的唯一值等于源值模 2n 其中 n 是用于表示目标类型的位数。 (C++20 起)]。

【讨论】:

  • 如果this 是正确的,int64_t 是一个“宽度正好为 64 位的有符号整数类型没有填充位并且对负值使用 2 的补码(仅当实现直接支持该类型时才提供)”我们是否可以假设如果提供,它是总是 2的补码?
  • @Bob__ 我已经检查了标准并且页面是正确的。呵呵,我不知道这是必需的。但为了清楚起见,我想我会留下“任何明智的二进制补码平台”的措辞。
  • 好吧,在这种情况下,我想引用标准可能是对您答案的一个很好的补充;)
  • @Bob__ 非常好,我完全忘记了!我想,基于此,有人可以说它甚至在 C++11 上也是独一无二的。如果有人感兴趣,我在我的答案中添加了我认为相关的引语……
  • @MichaelKenze 好吧,它说的是“实现定义的”。即使是 2 的补码,转换仍然是实现定义的。
【解决方案2】:

使用signedVec 结尾的值

std::vector<std::int64_t> signedVec( unsignedVec.begin(), unsignedVec.end() );

如果unsignedVec 中的对应值大于std::int64_t 可以表示的值,则将在C++11 中实现定义。否则,值将相同[conv.integral]/3

如果目标类型是有符号的,如果它可以在目标类型(和位域宽度)中表示,则值不变;否则,该值是实现定义的。

注意:C++11 通过 [headers]/4 从 C99 继承 std::int64_t 的定义。 int64_t 在 C99 [7.18.1.1]/1 中指定为(强调我的;感谢 @Bob__ 指出这一点):

typedef 名称intN_t 指定宽度为N无填充位和二进制补码表示的有符号整数类型

和[7.18.1.1]/3

这些类型是可选的。但是,如果实现提供了宽度为 8、16、32 或 64 位的整数类型,没有填充位,并且(对于有符号类型)具有二进制补码表示,则它应定义相应的 typedef 名称。

因此,虽然它在技术上仍然是实现定义的,但如果代码编译,这些值不太可能不唯一(只有在定义 std::int64_t 时才会如此,因为这是可选的)。由于int64_t 被指定为具有二进制补码表示,并且仅在实现支持该表示时才定义,因此转换以非预期方式表现将非常令人惊讶。我从来没有听说过一个编译器不会像预期的那样运行。此外,正如answer by @HolyBlackCat 中所指出的,从 C++20 [conv.integral]/3 开始需要所需的行为...

【讨论】:

    【解决方案3】:

    对于给定的代码,存在两种可能的情况:

    • 原始向量unsignedVec 的所有元素都小于或等于std::numeric_limits&lt;int64_t&gt;::max()。在这种情况下,目标向量元素将与原始向量元素相同,并且将保留它们的所有属性。
    • 原始向量中有大于std::numeric_limits&lt;int64_t&gt;::max() 的元素。在这种情况下,程序行为没有在标准中定义,由实现决定,任何事情都可能发生。

    【讨论】:

    • 不是实现定义的吗?
    • @SergeyA 答案说行为是未定义的,但它是实现定义的。 en.cppreference.com/w/cpp/language/…
    • @HolyBlackCat 用词不当,我的意思是没有定义。为了清楚起见,我进行了编辑。
    • 很抱歉,您的措辞仍然具有误导性。 “未在标准中定义”与说它是“未定义”相同,并且是不正确的,因为标准将其定义为“实现定义”并且因为 C++20 直接定义了它。 “任何事情都可能发生”至少具有误导性,因为它仅用于描述未定义的行为,而这种情况并非如此。
    • @SergeyA 在谈论 C++ 时经常使用“标准中未定义”和“任何事情都可能发生”的表达方式,它们具有非常清晰和精确的含义,与您试图传达的含义不同在你的回答中。这就是为什么我认为它具有误导性,特别是对于没有如此强大的语言掌握的人。我可以提议修改还是您更喜欢保持这种方式?
    猜你喜欢
    • 2012-12-16
    • 1970-01-01
    • 2016-06-03
    • 2018-04-21
    • 2010-09-13
    • 2023-03-18
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多