繁体   English   中英

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

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

我想更好地知道什么时候应该投。 C++中加、乘等的隐式类型转换规则有哪些,比如

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

等等...

表达式是否总是被评估为更精确的类型? Java 的规则是否不同? 如果我对这个问题的表述不准确,请纠正我。

在 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>

涉及float算术运算结果为float

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

更详细的答案。 看看 C++ 标准第 5/9 节的内容

许多期望算术或枚举类型的操作数的二元运算符会以类似的方式导致转换并产生结果类型。 目的是产生一个通用类型,它也是 result 的类型

这种模式称为通常的算术转换,其定义如下:

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

— 否则,如果任一操作数为双精度,则另一个应转换为双精度。

— 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。

— 否则,应在两个操作数上执行积分提升 (4.5)。54)

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

——否则,如果一个操作数是一个long int而另一个是unsigned int,那么如果一个long int可以表示一个unsigned int的所有值,那么这个unsigned int就应该被转换成一个long int; 否则两个操作数都应转换为 unsigned long int。

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

— 否则,如果任一操作数是无符号的,则另一个应转换为无符号。

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

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

这种模式称为通常的算术转换,其定义如下:

— 如果任一操作数是作用域枚举类型,则不执行任何转换; 如果另一个操作数不具有相同的类型,则表达式格式错误。

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

— 否则,如果任一操作数为双精度,则另一个应转换为双精度。

— 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。

— 否则,两个操作数都要进行积分提升。 然后将以下规则应用于提升的操作数:

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

— 否则,如果两个操作数都是有符号整数类型或者都是无符号整数类型,则将整数转换等级较小的操作数转换为等级较大的操作数的类型。

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

— 否则,如果有符号整数类型操作数的类型可以表示无符号整数类型操作数类型的所有值,则将无符号整数类型操作数转换为有符号整数类型操作数的类型。

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

请参阅此处获取经常更新的列表。

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

“操作的最小大小是 int。” - 这会很奇怪(有效支持 char/short 操作的架构呢?)这真的在 C++ 规范中吗?

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

3) 这条规定有时被称为“as-if”规则,因为只要结果好像要求已被遵守,就可以从可观察到的范围内确定,实施可以自由地无视标准的任何要求程序的行为。

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

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

例如,考虑unsigned char = unsigned char + unsigned char + unsigned char ,其中加法会溢出(假设每个值为 200)。 如果您升级为int ,您将获得 600,然后将其隐式转换为unsigned char ,这将包装模 256,从而得到 88 的最终结果。如果您没有进行此类促销,则必须包装在前两个加法之间,将问题从200 + 200 + 200144 + 200 ,即 344,减少到 88。 换句话说,程序不知道差异,因此编译器可以随意忽略如果操作数的排名低于int则要求在int执行中间操作。

这在加法、减法和乘法中普遍适用。 对于除法或模数而言,通常情况并非如此。

如果排除无符号类型,则有一个有序的层次结构:signed char、short、int、long、long long、float、double、long double。 首先,上面的 int 之前的任何内容都将转换为 int。 然后,在二元运算中,将排名较低的类型转换为较高的类型,结果将是较高的类型。 (您会注意到,从层次结构中,只要涉及浮点类型和整数类型,整数类型就会转换为浮点类型。)

无符号使事情变得有点复杂:它扰乱了排名,并且部分排名变得由实现定义。 因此,最好不要在同一个表达式中混合使用有符号和无符号。 (大多数 C++ 专家似乎避免无符号,除非涉及按位运算。至少,这是 Stroustrup 推荐的。)

我对问题的解决方案得到了 WA(错误答案),然后我将int之一更改为long long int并给出AC(accept) 以前,我试图做long long int += int * int ,在我将其纠正为long long int += long long int * int 我想出的谷歌搜索,

1.算术转换

类型转换的条件:

满足条件 ---> 转换

  • 任一操作数的类型为long double ---> 其他操作数转换为long double类型。

  • 不满足前面的条件,并且任一操作数的类型为double ---> 其他操作数转换为double类型。

  • 不满足前面的条件,并且任一操作数的类型为float ---> 其他操作数转换为float类型。

  • 不满足前面的条件(所有操作数都不是浮点类型)。 ---> 对操作数执行积分提升如下:

    • 如果任一操作数的类型为unsigned long ,则另一个操作数将转换为unsigned long类型。
    • 如果不满足前面的条件,并且如果其中一个操作数是long类型而另一个是unsigned int类型,则两个操作数都将转换为unsigned long类型。
    • 如果不满足前两个条件,并且其中一个操作数是long类型,则另一个操作数将转换为long类型。
    • 如果不满足上述三个条件,并且任一操作数的类型为unsigned int ,则另一个操作数将转换为unsigned int类型。
    • 如果上述条件都不满足,则两个操作数都将转换为int类型。

2 . 整数转换规则

  • 整数促销:

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

  • 整数转换等级:

    • 任何两个有符号整数类型都不应具有相同的等级,即使它们具有相同的表示形式。
    • 有符号整数类型的等级应大于精度较低的任何有符号整数类型的等级。
    • 军衔long long int应大于军衔更高的long int ,这应该比军衔更高的int ,这应该比军衔更高的short int ,这应该比军衔更高的signed char
    • 任何无符号整数类型的等级应等于相应的有符号整数类型(如果有)的等级。
    • 任何标准整数类型的秩都应大于具有相同宽度的任何扩展整数类型的秩。
    • char的等级应等于signed charunsigned char的等级。
    • 任何扩展有符号整数类型相对于具有相同精度的另一个扩展有符号整数类型的等级是实现定义的,但仍受用于确定整数转换等级的其他规则的约束。
    • 对于所有整数类型 T1、T2 和 T3,如果 T1 的秩大于 T2 且 T2 的秩大于 T3,则 T1 的秩大于 T3。
  • 通常的算术转换:

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

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

在涉及实数和整数的表达式中,整数将被提升为实数。 例如,在 int + float 中,表达式的类型是 float。

另一个区别与类型的能力有关。 例如,涉及一个 int 和一个 long int 的表达式将产生 long int 类型。

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

4.5 积分促销[conv.prom]
如果 int 可以表示源类型的所有值,则 char、signed char、unsigned char、short int 或 unsigned short int 类型的右值可以转换为 int 类型的右值; 其他-
明智的做法是,源右值可以转换为 unsigned int 类型的右值。
类型 wchar_t (3.9.1) 或枚举类型 (7.2) 的右值可以转换为第一个的右值
以下类型可以表示其基础类型的所有值:int、unsigned int、
长,或无符号长。
如果 int 可以表示所有,则整数位域 (9.6) 的右值可以转换为 int 类型的右值
位域的值; 否则,如果 unsigned int 可以表示,则可以将其转换为 unsigned int
重新发送位域的所有值。 如果位字段更大,则没有积分提升适用于它。 如果
位域有一个枚举类型,为了提升目的,它被视为该类型的任何其他值。
bool 类型的右值可以转换为 int 类型的右值,false 变为 0 和 true
成为一。
这些转换称为积分促销。

4.6 浮点提升【conv.fpprom】
float 类型的右值可以转换为 double 类型的右值。 值不变。
这种转换称为浮点提升。

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

只有一个同时涉及 int - 结果是 int : int / int = int

警告!

转换从左到右发生。

尝试这个:

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