C ++运算符中的隐式types转换规则
我想更好地知道我应该什么时候施放。 C ++中的隐式types转换规则在添加,相乘等方面是什么。例如,
int + float = ? int * float = ? float * int = ? int / float = ? float / int = ? int / int = ? int ^ float = ?
等等…
expression式总是被评估为更精确的types吗? Java的规则有所不同吗? 如果我的这个问题措辞不正确,请纠正我的错误。
在C ++操作符(对于PODtypes)中,总是作用于相同types的对象。
因此,如果他们不是一样的人将被提升为匹配另一个。
操作结果的types与操作数相同(转换后)。
If either is long double the other is promoted to long double If either is double the other is promoted to double If either is float the other is promoted to float If either is long long unsigned int the other is promoted to long long unsigned int If either is long long int the other is promoted to long long int If either is long unsigned int the other is promoted to long unsigned int If either is long int the other is promoted to long int If either is unsigned int the other is promoted to unsigned int If either is int the other is promoted to int Both operands are promoted to int
注意。 操作的最小尺寸是int
。 所以short
/ char
在操作完成之前被提升为int
。
在所有的expression式中, int
在执行操作之前都会被提升为float
。 操作的结果是一个float
。
int + float => float + float = float int * float => float * float = float float * int => float * float = float int / float => float / float = float float / int => float / float = float int / int = int int ^ float => <compiler error>
涉及float
算术运算结果为float
。
int + float = float int * float = float float * int = float int / float = float float / int = float int / int = int
有关更多详细的答案。 看看C ++标准第5/9节的内容
许多期望算术或枚举types的操作数的二元运算符以相似的方式导致转换和产生结果types。 目的是产生一个共同的types, 这也是结果的types 。
这种模式被称为通常的算术转换,其定义如下:
– 如果任一操作数的types是long double,则另一个操作数应转换为long double。
– 否则,如果其中一个操作数是双倍的,另一个将被转换为双倍。
– 否则,如果任一操作数是浮点数,则另一个操作数应转换为浮点数。
– 否则,整体促销(4.5)应在两个操作数上执行.54)
– 然后,如果任一操作数是无符号长整型,另一个将被转换为无符号长整型。
– 否则,如果一个操作数是一个long int而另一个是unsigned int,那么如果一个long int可以表示一个unsigned int的所有值,那么unsigned int将被转换为一个long int; 否则这两个操作数都将被转换为unsigned long int。
– 否则,如果其中一个操作数很长,另一个应转换为long。
– 否则,如果任一操作数是无符号的,则另一个应转换为无符号。
[注意:否则,唯一剩下的情况是两个操作数都是int]
由于其他答案不讨论在C + + 11的规则这里是一个。 从C ++ 11标准(草案n3337)§5/ 9:
这种模式被称为通常的算术转换 ,其定义如下:
– 如果任一操作数是范围枚举types,则不执行转换; 如果另一个操作数不具有相同的types,则expression式不合格。
– 如果任一操作数的types是long double,则另一个操作数应转换为long double。
– 否则,如果其中一个操作数是双倍的,另一个将被转换为双倍。
– 否则,如果任一操作数是浮点数,则另一个操作数应转换为浮点数。
– 否则,整体升级应在两个操作数上执行。 那么下面的规则应该适用于提升的操作数:
– 如果两个操作数具有相同的types,则不需要进一步转换。
– 否则,如果两个操作数都有符号整数types或两者都有无符号整数types,则整型转换等级types的操作数应转换为更高级别的操作数的types。
– 否则,如果具有无符号整数types的操作数的rank大于或等于另一个操作数的types的rank,则将带符号整数types的操作数转换为无符号整数types的操作数的types。
– 否则,如果具有有符号整数types的操作数的types可以表示具有无符号整数types的操作数types的所有值,则将具有无符号整数types的操作数转换为具有符号整数types的操作数的types。
– 否则,两个操作数都将转换为与带符号整数types的操作数types相对应的无符号整数types。
在这里看到一个经常更新的列表。
这个答案在很大程度上是由@RafałDowgird发表的:
“操作的最小尺寸是int。” – 这将是非常奇怪的(有关支持字符/短操作的体系结构呢?)这真的在C ++规范中吗?
请记住,C ++标准具有非常重要的“as-if”规则。 请参阅1.8节:程序执行:
3)这个规定有时被称为“假设”规则,因为只要结果是仿效了要求,就可以从可观察的事物中确定,实施可以自由地忽视标准的任何要求程序的行为。
编译器不能将int
设置为8位,即使它是最快的,因为标准要求16位最小int
。
因此,对于具有超快速8位运算的理论计算机来说,隐式提升为int
运算可能很重要。 但是,对于许多操作,您不能确定编译器是否以int
的精度执行操作,然后转换为char
来存储variables,或者操作是否始终以charforms完成。
例如,考虑unsigned char = unsigned char + unsigned char + unsigned char
,其中加法溢出(假设每个值为200)。 如果你提升为int
,你会得到600,然后隐式地将其转换为一个unsigned char
,这将会包装模256,从而得到88的最终结果。如果你没有这样的促销,你必须包装在前两个增加之间,这将把问题从200 + 200 + 200
到144 + 200
,即344,减less到88.换句话说,程序不知道差异,所以编译器可以自由地忽略如果操作数比int
小,则执行int
中间操作的任务。
加法,减法和乘法通常是这样的。 一般来说,分裂或模量是不正确的。
如果排除无符号types,则会有一个有序的层次结构:signed char,short,int,long,long long,float,double,long double。 首先,上面int之前的任何内容都将被转换为int。 然后,在二元操作中,排名较低的types将被转换为较高,结果将是较高的types。 (您会注意到,从层次结构中,无论何时涉及浮点数和整数types,整数types都将被转换为浮点types。)
无符号使事情变得复杂一点:扰乱了排名,排名的一部分变成了实现定义。 因此,最好不要在相同的expression式中混合使用有符号和无符号。 (大多数C ++专家似乎都避免未签名,除非涉及按位操作,也就是说,至lessStroustrupbuild议的是什么)。
我对问题的 解决scheme得到了WA(错误的答案),然后我改变了一个int
为long long int
,它给了AC(accept) 。 以前,我试图做long long int += int * int
,并在我纠正它long long int += long long int * int
。 谷歌search我想出了,
1. 算术转换
types转换的条件:
条件达到—>转换
-
操作数的types都是long double 。 —>其他操作数被转换为long doubletypes。
-
前面的条件不符合,或者操作数是doubletypes的。 —>其他操作数转换为doubletypes。
-
前面的条件不符合,或者操作数是浮点types。 —>其他操作数转换为floattypes。
-
先前条件不符合(操作数都不是浮动types)。 —>对操作数进行整体升级,如下所示:
- 如果任一操作数的types为无符号长整型 ,则另一操作数将转换为无符号长整型 。
- 如果前面的条件不符合,并且如果其中一个操作数的types为long ,而另一个的types为unsigned int ,则两个操作数都转换为unsigned longtypes。
- 如果前面两个条件不符合,并且其中一个操作数的types是long ,则另一个操作数的types转换为long 。
- 如果前三个条件不满足,并且其中一个操作数的types为unsigned int ,则另一个操作数转换为unsigned inttypes。
- 如果前面的条件都不符合,则两个操作数都转换为inttypes。
2。 整数转换规则
- 整数推广:
在对它们执行操作时提升小于int的整数types。 如果原始types的所有值都可以表示为int,则较小types的值将转换为int; 否则,它被转换为一个无符号的整数。 整数升级是作为通常算术转换的一部分应用于某些参数expression式; 一元+, – 和〜运算符的操作数; 和转换操作符的操作数。
-
整数转换等级:
- 没有两个有符号整数types应该具有相同的等级,即使它们具有相同的表示。
- 有符号整数types的秩应大于任何有精度低的有符号整数types的秩。
-
long long int
的级别应大于long long int
的级别,该级别应大于long int
的级别,该级别应大于short int
的级别,该级别应大于signed char
的级别。 - 任何无符号整数types的等级应等于相应的有符号整数types的等级(如果有的话)。
- 任何标准整数types的等级应该大于任何具有相同宽度的扩展整数types的等级。
-
char
的等级应该等于被signed char
和unsigned char
的等级。 - 任何扩展有符号整数types相对于另一个具有相同精度的扩展有符号整数types的等级是实现定义的,但是仍然受限于用于确定整数转换等级的其他规则。
- 对于所有整数typesT1,T2和T3,如果T1的排名大于T2,T2的排名大于T3,则T1的排名大于T3。
-
通常的算术转换:
- 如果两个操作数具有相同types,则不需要进一步转换。
- 如果两个操作数具有相同的整数types(有符号或无符号),则将较小整数转换等级的操作数转换为具有较高等级的操作数的types。
- 如果具有无符号整数types的操作数具有大于或等于另一操作数types的等级,则具有有符号整数types的操作数将转换为具有无符号整数types的操作数的types。
- 如果具有有符号整数types的操作数的types可以表示具有无符号整数types的操作数types的所有值,则将具有无符号整数types的操作数转换为具有有符号整数types的操作数的types。
- 否则,两个操作数都转换为与带符号整数types的操作数types相对应的无符号整数types。 具体操作可以添加或修改通常的算术运算的语义。
整个第4章谈到转换,但我认为你应该对这些主要感兴趣:
4.5积分促销 [conv.prom]
如果int可以表示源types的所有值,则可以将chartypes,signed char,unsigned char,short int或unsigned short int的右值转换为inttypes的右值; 其他-
明智的是,源的右值可以转换为无符号整型的右值。
可以将types为wchar_t(3.9.1)或枚举types(7.2)的右值转换为第一个右值
以下types可以表示其基础types的所有值:int,unsigned int,
长或无符号长。
如果int可以表示全部,则整数位域(9.6)的右值可以转换为inttypes的右值
位字段的值; 否则,它可以转换为无符号整型如果unsigned int可以rep-
憎恨比特场的所有值。 如果位域较大,则不会应用整数升级。 如果
位字段具有枚举types,为了提升目的,它被视为该types的任何其他值。
一个booltypes的右值可以被转换成一个inttypes的右值,其中false为零且为真
成为一个。
这些转换被称为积分促销。
4.6浮点提升 [conv.fpprom]
浮点types的右值可以转换为doubletypes的右值。 价值不变。
这种转换被称为浮点升级。
因此,所有涉及float的转换 – 结果都是float。
只有一个涉及int的结果是int:int / int = int
expression式的types(当不是两个部分是相同types的时候)将被转换为两者中最大的一个。 这里的问题是理解哪一个比另一个更大(它与字节的大小没有任何关系)。
在涉及实数和整数的expression式中,整数将被提升为实数。 例如,在int + float中,expression式的types是float。
另一个区别是与types的能力有关。 例如,涉及int和long int的expression式将导致long inttypes。
警告!
转换发生从左到右。
尝试这个:
int i = 3, j = 2; double k = 33; cout << k * j / i << endl; // prints 22 cout << j / i * k << endl; // prints 0