【问题标题】:c++ safeness of code with implicit conversion between signed and unsignedc++代码的安全性与有符号和无符号之间的隐式转换
【发布时间】:2019-04-10 09:26:35
【问题描述】:

根据herehere讨论的有符号和无符号整数类型之间隐式转换的规则,当将unsigned intint相加时,带符号的int首先转换为@987654326 @。

考虑,例如,以下最小程序

#include <iostream>

int main()
{
   unsigned int n = 2;
   int x = -1;

   std::cout << n + x << std::endl;

   return 0;
}

尽管如此,程序的输出是 1,正如预期的那样:x 首先转换为 unsigned int,然后与 n 相加会导致整数溢出,从而给出“正确”答案。

在类似上一个的代码中,如果我确定n + x 是正数,我可以假设unsigned int nint x 的总和给出预期值吗?

【问题讨论】:

  • 您是否在编译时启用所有警告?
  • @JGroven 这将如何影响答案?
  • 嗯,可能等等都是保证。编译器可能会警告可能的问题这一事实并不意味着,给定一个特定的标准,例如“如果我确定n + x 是肯定的”,它会,甚至它可能失败
  • @JGroven "如果编译器警告你正在做的事情,你可能不应该这样做。"呃,这是一个“警告”是有原因的——提醒你注意,以防万一。我遇到过很多情况,我在生产代码中的 WARNING: Unused variable X 实际上很好(可能是因为声明本身就产生了影响,或者编译器只是错误)。
  • 这将由实现定义。该标准表示有符号和无符号的位模式将相同,但不能保证 2 的补码。因此,如果这行得通,它将由实现定义。我相信 std::int8/16/32_t 保证是 2 的补码,所以它们总是可以工作的。

标签: c++


【解决方案1】:

在类似上一个的代码中,如果我确定 n + x 是正数,我可以假设 unsigned int n 和 int x 的总和给出期望值吗?

是的。

首先,将有符号值converted转为无符号,使用模运算:

如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n 其中 n 是用于表示无符号类型的位数)。

然后两个无符号值将是added 使用模运算:

无符号整数应遵守算术模 2n 的定律,其中 n 是该特定整数大小的值表示中的位数。

这意味着你会得到预期的答案。

即使结果在数学意义上是负数,C++ 中的结果也会是一个模等于负数的数。

请注意,我在这里假设您将两个相同大小的整数相加。

【讨论】:

    【解决方案2】:

    我认为您可以肯定,它不是实现定义的,尽管当涉及不使用二进制补码表示负值的系统时,此声明需要对标准进行一些解释。

    首先,让我们明确一点:无符号积分不会溢出,而是取模 2^nrOfBits 值(参见 online C++ standard draft):

    6.7.1 基本类型

    (7) 无符号整数应遵循算术模 2n 定律 其中 n 是该值表示中的位数 整数的特定大小。

    所以这只是一个负值nv 是否正确转换为无符号整数位模式nv(conv) 的问题,这样x + nv(conv) 将始终与x - nv 相同。对于使用二进制补码的系统来说,事情是很清楚的,因为二进制补码实际上是这样设计的,使得这种算术立即生效。

    对于使用其他负值表示的系统,我们必须仔细阅读标准:

    7.8 积分转换

    (2) 如果目标类型是无符号的,则结果值为 与源整数一致的最小无符号整数(模 2n 其中 n 是用于表示无符号类型的位数)。 [ 注意:在二进制补码表示中,此转换为 概念性的并且位模式没有变化(如果有 不截断)。 ——尾注]

    正如脚注明确指出的那样,在二进制补码表示中,位模式没有变化,我们可以假设在 2s 补码以外的系统中,将发生 real 转换,使得x + nv(conv) == x - nv

    所以由于 7.8 (2),我会说你的假​​设是有效的。

    【讨论】:

    • 算术是根据值而不是表示来定义的。系统是否使用 2 的补码都没有关系。 2 + -1 必须给 1 无论如何。
    • @M.M:是的,这就是结果不依赖于实现的原因,尽管在其他地方有人认为它可能只在 2s 补码的情况下才有效。
    猜你喜欢
    • 2013-04-06
    • 2013-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    相关资源
    最近更新 更多