c++操作符中的隐式类型转换规则

我想知道什么时候该投。在c++中,当进行加法、乘法等操作时,隐式类型转换规则是什么?例如,

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

等等……

表达式是否总是被计算为更精确的类型?Java的规则不同吗?

.

.

.
123927 次浏览

涉及float的算术运算结果为float

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

更多细节请回答。看看c++标准的§5/9节是怎么说的

许多二进制操作符 算术或枚举的操作数 类型导致转换和yield 以类似的方式生成类型。的 目的是产生一种常见的类型, 这也是结果的类型

这种模式被称为常规模式 算术转换 定义如下:

-如果任一操作数为long类型 双份,另一份应折算

-否则,如果 操作数为double,另一个为

.

.

-否则,if 其中一个操作数是float,另一个是float

-否则,积分提升 (4.5)应同时进行 operands.54) < / p >

-如果任一操作数 另一个是长吗

-否则,如果一个操作数是长 Int和另一个unsigned Int 如果一个长int可以表示所有的 的无符号整型的值 Unsigned int将被转换为a 长整型;否则两个操作数 应转换为unsigned long int。< / p >

-否则,如果任一操作数为 长了,其他的都要改 长。< / p >

-否则,如果任一操作数 是未署名的,其他应是

[注:否则,仅剩大小写为。 两个操作数都是int]

表达式的类型,当不是两个部分是相同类型时,将被转换为两者的最大的。这里的问题是理解哪一个比另一个大(它与字节大小无关)。

在包含实数和整数的表达式中,整数将升格为实数。例如,在int + float中,表达式的类型是float。

另一个区别与类型的能力有关。例如,包含int型和long int型的表达式的结果为long int型。

整个第4章都在讲转换,但我认为你应该对这些最感兴趣:

4.5积分促销 [conv.prom] < br > char、signed char、unsigned char、short int或unsigned short类型的右值 如果Int可以表示源类型的所有值,Int可以转换为Int类型的右值;——< br > 明智地,源右值可以转换为unsigned int类型的右值 类型为wchar_t(3.9.1)或枚举类型(7.2)的右值可以转换为第一个
的右值 以下类型可以表示其基础类型的所有值:int, unsigned int,
Long,或unsigned Long。
如果int可以表示所有
,则整型位域(9.6)的右值可以转换为int类型的右值 位域的值;否则,如果unsigned int可以代表-
,则可以转换为unsigned int 重发该位字段的所有值。如果位域更大,则不适用积分提升。如果< br > 位字段有一个枚举类型,为了提升,它被视为该类型的任何其他值 bool类型的右值可以转换为int类型的右值,其中false为零,true
成为一个。< br > 这些转换称为积分提升。< / p >

4.6浮点提升 [conv.fpprom] < br > float类型的右值可以转换为double类型的右值。值不变。
这种转换称为浮点提升。< / p >

因此,所有涉及浮点数的转换结果都是浮点数。

只有一个包含两个int -结果是int: Int / Int = Int

在c++中,运算符(用于POD类型)总是作用于相同类型的对象。
因此,如果它们不相同,其中一个将被提升到与另一个匹配。
操作结果的类型与操作数(转换后)相同
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

请注意。操作的最小大小是int。因此,在操作完成之前,short/char被提升为int

在你的所有表达式中,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>

如果排除unsigned类型,则存在有序类型 层次结构:signed char, short, int, long, long long, float, 双份,长双份。首先,所有在int之前的 上面的将被转换为int。然后,在二进制运算中, 排名较低的类型将转换为排名较高的类型,而 结果会越类型越高。(你会注意到,从 层次结构,任何时候浮点和整型都是 涉及到,将整型转换为浮点型 点类型。)< / p >

Unsigned使事情变得有点复杂:它扰乱了排名,并且 部分排名变成实现定义。因为 最好不要把有符号和无符号混合在一起 表达式。(大多数c++专家似乎都避免使用unsigned除非 涉及到按位操作。那至少是什么 Stroustrup建议。)< / p >

这个答案在很大程度上是针对@ rafajdowgird的评论:

"操作的最小大小是int。"-这太奇怪了 (那么有效支持char/short的架构呢 操作?)这真的在c++规范中吗?< / p >

请记住,c++标准有非常重要的“as-if”规则。参见第1.8节:程序执行:

这个条款有时被称为“as-if”规则,因为an 执行可以自由地忽略标准的任何要求 只要结果是满足了要求,就可以 这可以从程序的可观察行为中确定

编译器不能将int的大小设置为8位,即使它是最快的,因为标准要求int的最小值为16位。

因此,在具有超快8位运算的理论计算机的情况下,算术隐式提升到int可能很重要。然而,对于许多操作,你无法判断编译器是否真的以int的精度进行了操作,然后转换为char来存储在你的变量中,或者这些操作是否一直以char类型完成。

例如,考虑unsigned char = unsigned char + unsigned char + unsigned char,其中加法将溢出(让我们假设每个值为200)。如果提升到int,则会得到600,然后隐式向下转换为unsigned char,对256取模,从而得到88的最终结果。如果你没有做这样的提升,你必须在前两次添加之间进行换行,这将把问题从200 + 200 + 200减少到144 + 200,也就是344,再减少到88。换句话说,程序不知道区别,所以如果操作数的排名低于int,编译器可以自由地忽略在int中执行中间操作的要求。

这在一般的加法、减法和乘法中都是成立的。对于除法和模量来说,一般不是这样的。

由于其他答案都没有谈到c++ 11中的规则,这里有一个。来自c++ 11标准(草案n3337)§5/9(强调了差异):

这个模式被称为常用算术转换,定义如下:

-如果任一操作数为范围枚举类型,则不执行转换;如果另一个操作数没有相同的类型,则表达式为病态表达式。

-如果其中一个操作数为long double类型,则另一个操作数应转换为long double类型。

-否则,如果其中一个操作数为双精度,则另一个操作数将转换为双精度。

-否则,如果其中一个操作数为float,则另一个操作数将转换为float。

-否则,将对两个操作数执行积分提升。然后将下列规则应用于提升的操作数:

—如果两个操作数类型相同,则无需进行进一步转换。

-否则,如果两个操作数都是有符号整型或都是无符号整型,则 类型的转换秩较小的整数类型的操作数应转换为

-否则,如果具有无符号整数类型的操作数的秩大于或等于 另一个操作数的类型的秩,带符号整数类型的操作数将被转换为 无符号整型操作数的类型

-否则,如果带符号整型的操作数的类型可以表示无符号整型操作数类型的所有值,则无符号整型操作数必须 被转换为带符号整型的操作数类型

-否则,两个操作数都应转换为无符号整数类型 带符号整型的操作数类型

参见在这里获取频繁更新的列表。

我的解决方案问题得到了WA(错误答案),然后我将int中的一个更改为long long int,它给出了交流(接受)。之前,我尝试执行long long int += int * int,在我将其纠正为long long int += long long int * int之后。我在谷歌上搜了一下,

1. 算术转换

类型转换条件:

条件满足—>转换

  • 任意一个操作数的类型都是long double。——>其他操作数转换为类型long double

  • 不满足上述条件且任一操作数类型为double。——>其他操作数转换为类型double

  • 不满足上述条件且任一操作数类型为float。——>其他操作数转换为类型float

  • 不满足上述条件(操作数都不是浮点类型)。——>对操作数执行积分提升,如下所示:

    • 如果其中一个操作数类型为无符号长,则另一个操作数将转换为无符号长类型。
    • 如果上述条件不满足,并且其中一个操作数类型为,另一个操作数类型为无符号整型,则两个操作数都转换为无符号长
    • 如果上述两个条件不满足,且其中一个操作数类型为,则另一个操作数被转换为类型。
    • 如果上述三个条件都不满足,并且其中一个操作数类型为无符号整型,则另一个操作数将转换为无符号整型类型。
    • 如果上述条件均不满足,则两个操作数都转换为int类型。
    • 李< / ul > < / >

    2。整数转换规则

    • 整数的促销活动:

    小于int的整数类型在对其执行操作时被提升。如果原始类型的所有值都可以表示为int型,则较小类型的值转换为int型;否则,它将被转换为无符号整型。整数提升作为对某些参数表达式的常规算术转换的一部分应用;一元+、-和~操作符的操作数;和移位操作符的操作数。

    • 整数转换排名:

      • 没有两个有符号整数类型具有相同的秩,即使它们具有相同的表示。
      • 有符号整型的秩应大于任何精度较低的有符号整型的秩。
      • long long int的秩要大于long int的秩,long int的秩要大于int的秩,int的秩要大于short int的秩,short int的秩要大于signed char的秩。
      • 任何无符号整数类型的秩必须等于对应的有符号整数类型的秩(如果有的话)。
      • 任何标准整数类型的秩都应大于具有相同宽度的任何扩展整数类型的秩。
      • char的秩等于signed charunsigned char的秩。
      • 任何扩展有符号整数类型相对于具有相同精度的另一个扩展有符号整数类型的秩是由实现定义的,但仍然受制于确定整数转换秩的其他规则。
      • 对于所有整数类型T1、T2和T3,如果T1的秩大于T2且T2的秩大于T3,则T1的秩大于T3。
      • 李< / ul > < / >
      • 常用算术转换:

        • 如果两个操作数具有相同的类型,则不需要进一步转换。
        • 如果两个操作数都是相同的整数类型(有符号或无符号),则整数转换秩较小的操作数将转换为秩较大的操作数的类型。
        • 如果无符号整型的操作数的秩大于或等于另一个操作数的类型的秩,则有符号整型的操作数将转换为无符号整型的操作数的类型。
        • 如果带符号整型的操作数的类型可以表示带符号整型的操作数类型的所有值,则带符号整型的操作数将转换为带符号整型的操作数的类型。
        • 否则,两个操作数都转换为无符号整型,对应于带符号整型的操作数的类型。特定的操作可以增加或修改常用算术操作的语义。
        • 李< / ul > < / >

警告!

转换从左到右进行。

试试这个:

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