简体   繁体   English

C++ 运算符中的隐式类型转换规则

[英]Implicit type conversion rules in C++ operators

I want to be better about knowing when I should cast.我想更好地知道什么时候应该投。 What are the implicit type conversion rules in C++ when adding, multiplying, etc. For example, C++中加、乘等的隐式类型转换规则有哪些,比如

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

et cetera...等等...

Will the expression always be evaluated as the more precise type?表达式是否总是被评估为更精确的类型? Do the rules differ for Java? Java 的规则是否不同? Please correct me if I have worded this question inaccurately.如果我对这个问题的表述不准确,请纠正我。

In C++ operators (for POD types) always act on objects of the same type.在 C++ 运算符(用于 POD 类型)中,始终作用于相同类型的对象。
Thus if they are not the same one will be promoted to match the other.因此,如果它们不相同,则将提升一个以匹配另一个。
The type of the result of the operation is the same as operands (after conversion).运算结果的类型与操作数相同(转换后)。

if:
either is      long double       other is promoted >      long double
either is           double       other is promoted >           double
either is           float        other is promoted >           float
either is long long unsigned int other is promoted > long long unsigned int
either is long long          int other is promoted > long long          int
either is long      unsigned int other is promoted > long      unsigned int
either is long               int other is promoted > long               int
either is           unsigned int other is promoted >           unsigned int
either is                    int other is promoted >                    int

Otherwise:
both operands are promoted to int

Note.笔记。 The minimum size of operations is int .操作的最小大小是int So short / char are promoted to int before the operation is done.所以short / char在操作完成之前被提升为int

In all your expressions the int is promoted to a float before the operation is performed.在所有表达式中, int在执行操作之前被提升为float The result of the operation is a 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>

Arithmetic operations involving float results in float .涉及float算术运算结果为float

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int

For more detail answer.更详细的答案。 Look at what the section §5/9 from the C++ Standard says看看 C++ 标准第 5/9 节的内容

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way.许多期望算术或枚举类型的操作数的二元运算符会以类似的方式导致转换并产生结果类型。 The purpose is to yield a common type, which is also the type of the result .目的是产生一个通用类型,它也是 result 的类型

This pattern is called the usual arithmetic conversions, which are defined as follows:这种模式称为通常的算术转换,其定义如下:

— If either operand is of type long double, the other shall be converted to long double. — 如果任一操作数是 long double 类型,则另一个应转换为 long double。

— Otherwise, if either operand is double, the other shall be converted to double. — 否则,如果任一操作数为双精度,则另一个应转换为双精度。

— Otherwise, if either operand is float, the other shall be converted to float. — 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。

— Otherwise, the integral promotions (4.5) shall be performed on both operands.54) — 否则,应在两个操作数上执行积分提升 (4.5)。54)

— Then, if either operand is unsigned long the other shall be converted to unsigned long. — 然后,如果任一操作数是 unsigned long,则另一个应转换为 unsigned long。

— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent all the values of an unsigned int, the unsigned int shall be converted to a long int; ——否则,如果一个操作数是一个long int而另一个是unsigned int,那么如果一个long int可以表示一个unsigned int的所有值,那么这个unsigned int就应该被转换成一个long int; otherwise both operands shall be converted to unsigned long int.否则两个操作数都应转换为 unsigned long int。

— Otherwise, if either operand is long, the other shall be converted to long. — 否则,如果任一操作数为 long,则另一个应转换为 long。

— Otherwise, if either operand is unsigned, the other shall be converted to unsigned. — 否则,如果任一操作数是无符号的,则另一个应转换为无符号。

[Note: otherwise, the only remaining case is that both operands are int ] [注意:否则,唯一剩下的情况是两个操作数都是 int ]

Since the other answers don't talk about the rules in C++11 here's one.由于其他答案没有讨论 C++11 中的规则,这里是一个。 From C++11 standard (draft n3337) §5/9 (emphasized the difference):来自 C++11 标准(n3337 草案)§5/9(强调差异):

This pattern is called the usual arithmetic conversions , which are defined as follows:这种模式称为通常的算术转换,其定义如下:

— If either operand is of scoped enumeration type, no conversions are performed; — 如果任一操作数是作用域枚举类型,则不执行任何转换; if the other operand does not have the same type, the expression is ill-formed.如果另一个操作数不具有相同的类型,则表达式格式错误。

— If either operand is of type long double, the other shall be converted to long double. — 如果任一操作数是 long double 类型,则另一个应转换为 long double。

— Otherwise, if either operand is double, the other shall be converted to double. — 否则,如果任一操作数为双精度,则另一个应转换为双精度。

— Otherwise, if either operand is float, the other shall be converted to float. — 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。

— Otherwise, the integral promotions shall be performed on both operands. — 否则,两个操作数都要进行积分提升。 Then the following rules shall be applied to the promoted operands:然后将以下规则应用于提升的操作数:

— If both operands have the same type, no further conversion is needed. — 如果两个操作数的类型相同,则不需要进一步转换。

— Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank shall be converted to the type of the operand with greater rank. — 否则,如果两个操作数都是有符号整数类型或者都是无符号整数类型,则将整数转换等级较小的操作数转换为等级较大的操作数的类型。

— Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type. — 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则将具有符号整数类型的操作数转换为具有无符号整数类型的操作数的类型。

— Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type. — 否则,如果有符号整数类型操作数的类型可以表示无符号整数类型操作数类型的所有值,则将无符号整数类型操作数转换为有符号整数类型操作数的类型。

— Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type. — 否则,两个操作数都应转换为与带符号整数类型的操作数类型对应的无符号整数类型。

See here for a list that's frequently updated.请参阅此处获取经常更新的列表。

This answer is directed in large part at a comment made by @RafałDowgird:这个答案在很大程度上是针对@RafałDowgird 的评论:

"The minimum size of operations is int." “操作的最小大小是 int。” - This would be very strange (what about architectures that efficiently support char/short operations?) Is this really in the C++ spec? - 这会很奇怪(有效支持 char/short 操作的架构呢?)这真的在 C++ 规范中吗?

Keep in mind that the C++ standard has the all-important "as-if" rule.请记住,C++ 标准具有非常重要的“as-if”规则。 See section 1.8: Program Execution:请参阅第 1.8 节:程序执行:

3) This provision is sometimes called the "as-if" rule, because an implementation is free to disregard any requirement of the Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program. 3) 这条规定有时被称为“as-if”规则,因为只要结果好像要求已被遵守,就可以从可观察到的范围内确定,实施可以自由地无视标准的任何要求程序的行为。

The compiler cannot set an int to be 8 bits in size, even if it were the fastest, since the standard mandates a 16-bit minimum int .编译器不能将int大小设置为 8 位,即使它是最快的,因为标准要求最小为 16 位的int

Therefore, in the case of a theoretical computer with super-fast 8-bit operations, the implicit promotion to int for arithmetic could matter.因此,在具有超快 8 位运算的理论计算机的情况下,隐式提升到int以进行算术运算可能很重要。 However, for many operations, you cannot tell if the compiler actually did the operations in the precision of an int and then converted to a char to store in your variable, or if the operations were done in char all along.但是,对于许多操作,您无法判断编译器是否确实以int的精度进行了操作,然后将其转换为char以存储在您的变量中,或者这些操作是否一直在 char 中完成。

For example, consider unsigned char = unsigned char + unsigned char + unsigned char , where addition would overflow (let's assume a value of 200 for each).例如,考虑unsigned char = unsigned char + unsigned char + unsigned char ,其中加法会溢出(假设每个值为 200)。 If you promoted to int , you would get 600, which would then be implicitly down cast into an unsigned char , which would wrap modulo 256, thus giving a final result of 88. If you did no such promotions,you'd have to wrap between the first two additions, which would reduce the problem from 200 + 200 + 200 to 144 + 200 , which is 344, which reduces to 88. In other words, the program does not know the difference, so the compiler is free to ignore the mandate to perform intermediate operations in int if the operands have a lower ranking than int .如果您升级为int ,您将获得 600,然后将其隐式转换为unsigned char ,这将包装模 256,从而得到 88 的最终结果。如果您没有进行此类促销,则必须包装在前两个加法之间,将问题从200 + 200 + 200144 + 200 ,即 344,减少到 88。 换句话说,程序不知道差异,因此编译器可以随意忽略如果操作数的排名低于int则要求在int执行中间操作。

This is true in general of addition, subtraction, and multiplication.这在加法、减法和乘法中普遍适用。 It is not true in general for division or modulus.对于除法或模数而言,通常情况并非如此。

If you exclude the unsigned types, there is an ordered hierarchy: signed char, short, int, long, long long, float, double, long double.如果排除无符号类型,则有一个有序的层次结构:signed char、short、int、long、long long、float、double、long double。 First, anything coming before int in the above will be converted to int.首先,上面的 int 之前的任何内容都将转换为 int。 Then, in a binary operation, the lower ranked type will be converted to the higher, and the results will be the type of the higher.然后,在二元运算中,将排名较低的类型转换为较高的类型,结果将是较高的类型。 (You'll note that, from the hierarchy, anytime a floating point and an integral type are involved, the integral type will be converted to the floating point type.) (您会注意到,从层次结构中,只要涉及浮点类型和整数类型,整数类型就会转换为浮点类型。)

Unsigned complicates things a bit: it perturbs the ranking, and parts of the ranking become implementation defined.无符号使事情变得有点复杂:它扰乱了排名,并且部分排名变得由实现定义。 Because of this, it's best to not mix signed and unsigned in the same expression.因此,最好不要在同一个表达式中混合使用有符号和无符号。 (Most C++ experts seem to avoid unsigned unless bitwise operations are involved. That is, at least, what Stroustrup recommends.) (大多数 C++ 专家似乎避免无符号,除非涉及按位运算。至少,这是 Stroustrup 推荐的。)

My solution to the problem got WA(wrong answer), then i changed one of int to long long int and it gave AC(accept) .我对问题的解决方案得到了 WA(错误答案),然后我将int之一更改为long long int并给出AC(accept) Previously, I was trying to do long long int += int * int , and after I rectify it to long long int += long long int * int .以前,我试图做long long int += int * int ,在我将其纠正为long long int += long long int * int Googling I came up with,我想出的谷歌搜索,

1. Arithmetic Conversions 1.算术转换

Conditions for Type Conversion:类型转换的条件:

Conditions Met ---> Conversion满足条件 ---> 转换

  • Either operand is of type long double .任一操作数的类型为long double ---> Other operand is converted to type long double . ---> 其他操作数转换为long double类型。

  • Preceding condition not met and either operand is of type double .不满足前面的条件,并且任一操作数的类型为double ---> Other operand is converted to type double . ---> 其他操作数转换为double类型。

  • Preceding conditions not met and either operand is of type float .不满足前面的条件,并且任一操作数的类型为float ---> Other operand is converted to type float . ---> 其他操作数转换为float类型。

  • Preceding conditions not met (none of the operands are of floating types).不满足前面的条件(所有操作数都不是浮点类型)。 ---> Integral promotions are performed on the operands as follows: ---> 对操作数执行积分提升如下:

    • If either operand is of type unsigned long , the other operand is converted to type unsigned long .如果任一操作数的类型为unsigned long ,则另一个操作数将转换为unsigned long类型。
    • If preceding condition not met, and if either operand is of type long and the other of type unsigned int , both operands are converted to type unsigned long .如果不满足前面的条件,并且如果其中一个操作数是long类型而另一个是unsigned int类型,则两个操作数都将转换为unsigned long类型。
    • If the preceding two conditions are not met, and if either operand is of type long , t he other operand is converted to type long .如果不满足前两个条件,并且其中一个操作数是long类型,则另一个操作数将转换为long类型。
    • If the preceding three conditions are not met, and if either operand is of type unsigned int , the other operand is converted to type unsigned int .如果不满足上述三个条件,并且任一操作数的类型为unsigned int ,则另一个操作数将转换为unsigned int类型。
    • If none of the preceding conditions are met, both operands are converted to type int .如果上述条件都不满足,则两个操作数都将转换为int类型。

2 . 2 . Integer conversion rules 整数转换规则

  • Integer Promotions:整数促销:

Integer types smaller than int are promoted when an operation is performed on them.当对它们执行操作时,会提升小于 int 的整数类型。 If all values of the original type can be represented as an int, the value of the smaller type is converted to an int;如果原始类型的所有值都可以表示为int,则将较小类型的值转换为int; otherwise, it is converted to an unsigned int.否则,它被转换为无符号整数。 Integer promotions are applied as part of the usual arithmetic conversions to certain argument expressions;整数提升作为通常算术转换的一部分应用于某些参数表达式; operands of the unary +, -, and ~ operators;一元 +、- 和 ~ 运算符的操作数; and operands of the shift operators.和移位运算符的操作数。

  • Integer Conversion Rank:整数转换等级:

    • No two signed integer types shall have the same rank, even if they have the same representation.任何两个有符号整数类型都不应具有相同的等级,即使它们具有相同的表示形式。
    • The rank of a signed integer type shall be greater than the rank of any signed integer type with less precision.有符号整数类型的等级应大于精度较低的任何有符号整数类型的等级。
    • The rank of long long int shall be greater than the rank of long int , which shall be greater than the rank of int , which shall be greater than the rank of short int , which shall be greater than the rank of signed char .军衔long long int应大于军衔更高的long int ,这应该比军衔更高的int ,这应该比军衔更高的short int ,这应该比军衔更高的signed char
    • The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type, if any.任何无符号整数类型的等级应等于相应的有符号整数类型(如果有)的等级。
    • The rank of any standard integer type shall be greater than the rank of any extended integer type with the same width.任何标准整数类型的秩都应大于具有相同宽度的任何扩展整数类型的秩。
    • The rank of char shall equal the rank of signed char and unsigned char . char的等级应等于signed charunsigned char的等级。
    • The rank of any extended signed integer type relative to another extended signed integer type with the same precision is implementation-defined but still subject to the other rules for determining the integer conversion rank.任何扩展有符号整数类型相对于具有相同精度的另一个扩展有符号整数类型的等级是实现定义的,但仍受用于确定整数转换等级的其他规则的约束。
    • For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3, then T1 has greater rank than T3.对于所有整数类型 T1、T2 和 T3,如果 T1 的秩大于 T2 且 T2 的秩大于 T3,则 T1 的秩大于 T3。
  • Usual Arithmetic Conversions:通常的算术转换:

    • If both operands have the same type, no further conversion is needed.如果两个操作数的类型相同,则不需要进一步转换。
    • If both operands are of the same integer type (signed or unsigned), the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.如果两个操作数都是相同的整数类型(有符号或无符号),则将整数转换等级较小的操作数转换为等级较大的操作数的类型。
    • If the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type is converted to the type of the operand with unsigned integer type.如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则将具有符号整数类型的操作数转换为具有无符号整数类型的操作数的类型。
    • If the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type is converted to the type of the operand with signed integer type.如果有符号整数类型操作数的类型可以表示无符号整数类型操作数类型的所有值,则将无符号整数类型操作数转换为有符号整数类型操作数的类型。
    • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.否则,两个操作数都被转换为与带符号整数类型的操作数的类型对应的无符号整数类型。 Specific operations can add to or modify the semantics of the usual arithmetic operations.特定运算可以添加或修改通常算术运算的语义。

The type of the expression, when not both parts are of the same type, will be converted to the biggest of both.表达式的类型,当两个部分不是相同类型时,将转换为两者中最大的。 The problem here is to understand which one is bigger than the other (it does not have anything to do with size in bytes).这里的问题是要了解哪个比另一个大(它与字节大小无关)。

In expressions in which a real number and an integer number are involved, the integer will be promoted to real number.在涉及实数和整数的表达式中,整数将被提升为实数。 For example, in int + float, the type of the expression is float.例如,在 int + float 中,表达式的类型是 float。

The other difference are related to the capability of the type.另一个区别与类型的能力有关。 For example, an expression involving an int and a long int will result of type long int.例如,涉及一个 int 和一个 long int 的表达式将产生 long int 类型。

Whole chapter 4 talks about conversions, but I think you should be mostly interested in these :整个第 4 章都在讨论转换,但我认为您应该对这些最感兴趣:

4.5 Integral promotions [conv.prom] 4.5 积分促销[conv.prom]
An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be converted to an rvalue of type int if int can represent all the values of the source type;如果 int 可以表示源类型的所有值,则 char、signed char、unsigned char、short int 或 unsigned short int 类型的右值可以转换为 int 类型的右值; other-其他-
wise, the source rvalue can be converted to an rvalue of type unsigned int.明智的做法是,源右值可以转换为 unsigned int 类型的右值。
An rvalue of type wchar_t (3.9.1) or an enumeration type (7.2) can be converted to an rvalue of the first类型 wchar_t (3.9.1) 或枚举类型 (7.2) 的右值可以转换为第一个的右值
of the following types that can represent all the values of its underlying type: int, unsigned int,以下类型可以表示其基础类型的所有值:int、unsigned int、
long, or unsigned long.长,或无符号长。
An rvalue for an integral bit-field (9.6) can be converted to an rvalue of type int if int can represent all如果 int 可以表示所有,则整数位域 (9.6) 的右值可以转换为 int 类型的右值
the values of the bit-field;位域的值; otherwise, it can be converted to unsigned int if unsigned int can rep-否则,如果 unsigned int 可以表示,则可以将其转换为 unsigned int
resent all the values of the bit-field.重新发送位域的所有值。 If the bit-field is larger yet, no integral promotion applies to it.如果位字段更大,则没有积分提升适用于它。 If the如果
bit-field has an enumerated type, it is treated as any other value of that type for promotion purposes.位域有一个枚举类型,为了提升目的,它被视为该类型的任何其他值。
An rvalue of type bool can be converted to an rvalue of type int, with false becoming zero and true bool 类型的右值可以转换为 int 类型的右值,false 变为 0 和 true
becoming one.成为一。
These conversions are called integral promotions.这些转换称为积分促销。

4.6 Floating point promotion [conv.fpprom] 4.6 浮点提升【conv.fpprom】
An rvalue of type float can be converted to an rvalue of type double. float 类型的右值可以转换为 double 类型的右值。 The value is unchanged.值不变。
This conversion is called floating point promotion.这种转换称为浮点提升。

Therefore, all conversions involving float - the result is float.因此,所有涉及浮点数的转换——结果都是浮点数。

Only the one involving both int - the result is int : int / int = int只有一个同时涉及 int - 结果是 int : int / int = int

Caveat!警告!

The conversions occur from left to right.转换从左到右发生。

Try this:尝试这个:

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM