提问人:francesco 提问时间:11/7/2018 更新时间:11/7/2018 访问量:493
具有 signed 和 unsigned 之间隐式转换的代码的 C++ 安全性
c++ safeness of code with implicit conversion between signed and unsigned
问:
根据此处和此处讨论的有符号和无符号整数类型之间的隐式转换规则,当用 a 求和 时,有符号首先转换为 .unsigned int
int
int
unsigned int
例如,考虑以下最小程序
#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 n
int x
答:
在像前面这样的代码中,如果我确定 n + x 是正数,我可以假设无符号 int n 和 int x 的总和给出了预期值吗?
是的。
首先,使用模算术将有符号值转换为无符号值:
如果目标类型为无符号,则结果值是与源整数全等的最小无符号整数(模 2n,其中 n 是用于表示无符号类型的位数)。
然后使用模算术将两个无符号值相加:
无符号整数应遵守算术模 2 n 定律,其中n 是该特定大小的整数的值表示中的位数。
这意味着你会得到预期的答案。
甚至,如果结果在数学意义上是负数,则C++中的结果将是一个模等于负数的数字。
请注意,我在这里假设您添加两个相同大小的整数。
我认为您可以确定,并且它没有定义实现,尽管当涉及到不使用二补码表示负值的系统时,此声明需要对标准进行一些解释。
首先,让我们陈述清楚的事情:无符号积分不会溢出,而是取模 2^nrOfBits 值(参见这个在线 C++ 标准草案):
6.7.1 基本类型
(7)无符号整数应服从算术模2n定律 其中 n 是该值表示中的位数 整数的特定大小。
因此,这只是一个负值是否被正确转换为无符号整数位模式的问题,以便始终与 相同。对于使用二进制补码的系统,事情很清楚,因为二号补码实际上被设计成这种算术立即起作用。nv
nv(conv)
x + nv(conv)
x - nv
对于使用其他负值表示的系统,我们必须仔细阅读该标准:
7.8 积分转换
(2) 如果目标类型为无符号,则结果值为 与源整数全等的最小无符号整数(模 2n 其中 n 是用于表示无符号类型的位数)。[ 注意:在二进制补码表示中,此转换为 概念性,并且位模式没有变化(如果有 notruncation)。——尾注]
正如脚注明确指出的那样,在二的补码表示中,位模式没有变化,我们可以假设在除 2s 补码以外的系统中,将发生真正的转换,使得 .x + nv(conv) == x - nv
因此,由于 7.8 (2),我会说您的假设是有效的。
评论
2 + -1
1
上一个:C++ 泛型编译时 for 循环
下一个:-O1 改变浮点数学
评论
n + x
是正的”,它会,甚至它可能会失败WARNING: Unused variable X
std::int8/16/32_t