当我在 C++ 中混合有符号和无符号类型时会发生什么?

问题描述 投票:0回答:3

我对类型转换有一些疑问,你能解释一下这样的表达式中会发生什么吗:

unsigned int u = 10; 
int a = -42; 
std::cout << u - a << std::endl;

在这里,我知道如果我在有两个数学运算符时应用规则,结果将是

52

但是,我想知道当编译器必须将 a 转换为无符号值并创建无符号类型的临时对象时会发生什么,之后会发生什么?现在的表达式应该是

10 - 4294967254

c++ expression unsigned built-in-types
3个回答
45
投票

简单来说,如果混合相同等级的类型(按

int
long int
long long int
的顺序),则无符号类型“获胜”,并且计算将在该无符号类型内执行。结果是相同的无符号类型。

如果混合不同等级的类型,如果等级较高的类型可以代表等级较低的类型的所有值,则等级较高的类型“获胜”。计算是在该类型内执行的。结果就是这样的。

最后,如果较高排序类型不能表示较低排序类型的所有值,则使用较高排序类型的无符号版本。结果就是这样的。

在您的情况下,您混合了相同等级的类型(

int
unsigned int
),这意味着整个表达式在
unsigned int
类型内求值。正如您正确所述,表达式现在是
10 - 4294967254
(对于 32 位
int
)。无符号类型遵循以
2^32
(
4294967296
) 作为模的模算术规则。如果你仔细计算一下结果(可以用算术表示为
10 - 4294967254 + 4294967296
),结果会是预期的
52


10
投票
  1. 根据标准转换规则,
    signed
    类型
    a
    在减法之前会转换为
    unsigned
    类型。该转换根据 [conv.integral] p3:
  2. 发生

否则,结果是目标类型的唯一值,该值与源整数模 2N 一致,其中 N 是目标类型的宽度。

在代数上,

a
成为一个非常大的正数,并且肯定大于
u

  1. u - a
    是一个无名临时对象,属于
    unsigned
    类型。 (您可以通过编写
    auto t = u - a
    并在调试器中检查
    t
    的类型来验证这一点。)从数学上讲,这首先是一个负数,但在隐式转换为
    unsigned
    类型之后,类似于上面的环绕规则被调用。

简而言之,这两个转换操作具有相等且相反的效果,结果将是

52
。实际上,编译器可能会优化所有这些转换。


-3
投票

这是反汇编代码,其中表示:首先将

-42
设置为其补码并执行子操作。所以结果是
10 + 42

0x0000000000400835 <+8>:    movl   $0xa,-0xc(%rbp)
0x000000000040083c <+15>:   movl   $0xffffffd6,-0x8(%rbp)
0x0000000000400843 <+22>:   mov    -0x8(%rbp),%eax
0x0000000000400846 <+25>:   mov    -0xc(%rbp),%edx
0x0000000000400849 <+28>:   sub    %eax,%edx
0x000000000040084b <+30>:   mov    %edx,%eax`
© www.soinside.com 2019 - 2024. All rights reserved.