我对类型转换有一些疑问,你能解释一下在这样的表达式中会发生什么吗?
unsigned int u = 10; int a = -42; std::cout << u - a << std::endl;
这里我知道,如果我应用规则,当我们有两个数学运算符时,结果将是52。但是我想知道当编译器将a转换为unsigned值时会发生什么,创建了一个unsigned类型的临时变量,之后会发生什么?表达式现在应该是10-4294967254。
hmtdttj41#
简单地说,如果你混合了相同等级的类型(按照int,long int,long long int的顺序),无符号类型“获胜”,计算在该无符号类型内执行。结果是相同的无符号类型。如果你混合了不同等级的类型,那么等级较高的类型“获胜”,如果它可以表示等级较低的类型的所有值。在该类型中执行计算。结果就是这种类型。最后,如果排名较高的类型不能表示排名较低的类型的所有值,则使用排名较高的类型的无符号版本。结果就是这种类型。在你的例子中,你混合了相同等级的类型(int和unsigned int),这意味着整个表达式在unsigned int类型中计算。正如您正确指出的那样,表达式现在是10 - 4294967254(对于32位int)。无符号类型遵循以2^32(4294967296)为模的模算术规则。如果仔细计算结果(可以用算术表示为10 - 4294967254 + 4294967296),结果将是预期的52。
int
long int
long long int
unsigned int
10 - 4294967254
2^32
4294967296
10 - 4294967254 + 4294967296
52
ilmyapht2#
1)由于标准的提升规则,signed类型a在减法之前被提升为unsigned类型。这种提升是根据以下规则(C++标准4.7/2)进行的:如果目标类型是无符号的,则结果值是与源整数全等的最小无符号整数(模2n,其中n是用于表示无符号类型的位数)。代数上a成为一个非常大的正数,肯定大于u。2)u - a是一个匿名临时,并且将是unsigned类型。(您可以通过编写auto t = u - a并在调试器中检查t的类型来验证这一点。)从数学上讲,这将是一个负数,但在隐式转换为无符号类型时,会调用类似于上面的回绕规则。简而言之,两个转换操作具有相等且相反的效果,并且结果将是52。在实践中,编译器可能会优化所有这些转换。
signed
a
unsigned
u
u - a
auto t = u - a
t
ipakzgxi3#
这里是反汇编代码说:它首先将-42设置为其补码并进行子运算。所以结果是10 + 420x0000000000400835 <+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
-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
3条答案
按热度按时间hmtdttj41#
简单地说,如果你混合了相同等级的类型(按照
int
,long int
,long long int
的顺序),无符号类型“获胜”,计算在该无符号类型内执行。结果是相同的无符号类型。如果你混合了不同等级的类型,那么等级较高的类型“获胜”,如果它可以表示等级较低的类型的所有值。在该类型中执行计算。结果就是这种类型。
最后,如果排名较高的类型不能表示排名较低的类型的所有值,则使用排名较高的类型的无符号版本。结果就是这种类型。
在你的例子中,你混合了相同等级的类型(
int
和unsigned int
),这意味着整个表达式在unsigned int
类型中计算。正如您正确指出的那样,表达式现在是10 - 4294967254
(对于32位int
)。无符号类型遵循以2^32
(4294967296
)为模的模算术规则。如果仔细计算结果(可以用算术表示为10 - 4294967254 + 4294967296
),结果将是预期的52
。ilmyapht2#
1)由于标准的提升规则,
signed
类型a
在减法之前被提升为unsigned
类型。这种提升是根据以下规则(C++标准4.7/2)进行的:如果目标类型是无符号的,则结果值是与源整数全等的最小无符号整数(模2n,其中n是用于表示无符号类型的位数)。
代数上
a
成为一个非常大的正数,肯定大于u
。2)
u - a
是一个匿名临时,并且将是unsigned类型。(您可以通过编写auto t = u - a
并在调试器中检查t
的类型来验证这一点。)从数学上讲,这将是一个负数,但在隐式转换为无符号类型时,会调用类似于上面的回绕规则。简而言之,两个转换操作具有相等且相反的效果,并且结果将是52。在实践中,编译器可能会优化所有这些转换。
ipakzgxi3#
这里是反汇编代码说:
它首先将
-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