为了账号安全,请及时绑定邮箱和手机立即绑定

当二元运算符两边的签名不同时,促销规则如何工作?

当二元运算符两边的签名不同时,促销规则如何工作?

C++
慕码人8056858 2019-08-27 16:40:48
当二元运算符两边的签名不同时,促销规则如何工作?考虑以下程序:// http://ideone.com/4I0dT#include <limits>#include <iostream>int main(){     int max = std::numeric_limits<int>::max();     unsigned int one = 1;     unsigned int result = max + one;     std::cout << result;}和// http://ideone.com/UBuFZ#include <limits>#include <iostream>int main(){     unsigned int us = 42;     int neg = -43;     int result = us + neg;     std::cout << result;}+运算符如何“知道”返回哪个正确的类型?一般的规则是把所有的参数转换为最广泛的类型,但在这里没有明确的“赢家”之间int和unsigned int。在第一种情况下,unsigned int必须选择作为结果operator+,因为我得到了结果2147483648。在第二种情况下,它必须选择int,因为我得到了结果-1。然而,在一般情况下,我没有看到这是如何可判定的。这是我看到的未定义的行为还是其他什么?
查看完整描述

3 回答

?
忽然笑

TA贡献1806条经验 获得超5个赞

这在§5/ 9中明确概述:

许多期望算术或枚举类型的操作数的二元运算符会以类似的方式引起转换并产生结果类型。目的是产生一个通用类型,它也是结果的类型。这种模式称为通常的算术转换,定义如下:

  • 如果任一操作数是类型long double,则另一个操作数应转换为long double

  • 否则,如果任一操作数是double,则另一个操作数应转换为double

  • 否则,如果任一操作数是float,则另一个操作数应转换为float

  • 否则,应对两个操作数执行整体促销。

  • 然后,如果任一操作数是unsigned long另一个应转换为unsigned long

  • 否则,如果一个操作数是a long int和另一个unsigned int,那么如果a long int可以表示a的所有值unsigned intunsigned int则应转换为a long int; 否则两个操作数都应转换为unsigned long int

  • 否则,如果任一操作数是long,则另一个操作数应转换为long

  • 否则,如果任一操作数是unsigned,则另一个操作数应转换为unsigned

注意:否则,唯一剩下的情况是两个操作数都是int]

在两个场景中,结果operator+都是unsigned。因此,第二种情况是有效的:

int result = static_cast<int>(us + static_cast<unsigned>(neg));

因为在这种情况下,值us + neg不能表示int,值result是实现定义的 - §4.7/ 3:

如果目标类型已签名,则如果可以在目标类型(和位字段宽度)中表示该值,则该值不会更改; 否则,该值是实现定义的。


查看完整回答
反对 回复 2019-08-27
?
侃侃无极

TA贡献2051条经验 获得超10个赞

在C标准化之前,编译器之间存在差异 - 一些遵循“保值”规则,另一些遵循“签署保留”规则。保留符号意味着如果任一操作数是无符号的,则结果是无符号的。这很简单,但有时会给出相当惊人的结果(特别是当负数转换为无符号时)。

C对更复杂的“保值”规则进行了标准化。在保值规则下,促销可以/确实取决于类型的实际范围,因此您可以在不同的编译器上获得不同的结果。例如,在大多数MS-DOS编译器上,它们int的大小shortlong它们的大小相同。在许多当前系统int上,它们的大小与之相同long,并且short两者都不同。使用保值规则,这些可以导致促销类型在两者之间不同。

值保留规则的基本思想是,如果可以表示较小类型的所有值,它将提升为更大的签名类型。例如,16位unsigned short可以提升为32位signed int,因为每个可能的值unsigned short都可以表示为a signed int。当且仅当需要保留较小类型的值时,类型将被提升为无符号类型(例如,如果unsigned shortsigned int都是16位,则a signed int不能代表所有可能的值unsigned short,因此unsigned short将被提升为unsigned int)。

当您按原样分配结果时,无论如何都会将结果转换为目标类型,因此大多数情况都会产生相对较小的差异 - 至少在大多数情况下,它只会将位复制到结果中,并且由您来决定是将其解释为已签名还是未签名。

当你没有分配比较结果时,事情会变得非常难看。例如:

unsigned int a = 5;signed int b = -5;if (a > b)
    printf("Of course");else
    printf("What!");

在符号保留规则下,b将被提升为无符号,并且在此过程中变得相等UINT_MAX - 4,所以“什么!” if将采取的腿。使用保值规则,您可以设法产生一些奇怪的结果,但是1)主要在类似DOS的系统中,int其大小short与2 相同,并且2)无论如何通常都难以做到。


查看完整回答
反对 回复 2019-08-27
?
慕村225694

TA贡献1880条经验 获得超4个赞

它会选择你输入结果的任何类型,或者至少cout在输出过程中尊重那种类型。

我不记得肯定,但我认为C ++编译器为两者生成相同的算术代码,它只是比较和输出关心符号。


查看完整回答
反对 回复 2019-08-27
  • 3 回答
  • 0 关注
  • 375 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信