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

Mat*_*tag 156 c++ casting implicit

我想知道什么时候应该投出更好.在添加,乘法等时,C++中的隐式类型转换规则是什么.例如,

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?
Run Code Online (Sandbox Code Playgroud)

等等...

表达式是否总是被评估为更精确的类型?Java的规则有所不同吗?如果我不准确地说出这个问题,请纠正我.

Mar*_*ork 206

在C++中,运算符(对于POD类型)始终作用于相同类型的对象.
因此,如果它们不相同,那么将提升以匹配另一个.
操作结果的类型与操作数相同(转换后).

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
Run Code Online (Sandbox Code Playgroud)

注意.最小的操作规模是int.因此short/ 在操作完成之前char被提升int.

在所有表达式中,在执行操作之前将其int提升为a float.操作的结果是a 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>
Run Code Online (Sandbox Code Playgroud)

  • 问题示例"**int被提升为unsigned int**":`((int)4) - ((unsigned int)5)`将导致32位整数和32位无符号整数的"4294967295". (9认同)
  • @Rafal:是的.int应该是在特定平台上操作的最有效的整数类型.char必须始终为1,但short可以与int相同. (3认同)
  • @Rafał:是的,这很奇怪,而且它是在标准中的。在很多情况下,您描述的架构可以使用其超高效的“char”类型。如果将“char + char”的值分配给“char”,那么它可以只在“char”中进行算术运算,例如回绕。但是,如果结果分配给“int”,那么它必须在足够大的类型中进行算术,以便在超过“CHAR_MAX”时获得正确的结果。 (2认同)
  • 我只想强调以下事实:** int被提升为unsigned int ** !!!我与bug纠缠了好几天,因为我的印象是,两者都将被“提升”为int或long,因此可能的负面结果不会引起下溢/环绕。 (2认同)

Naw*_*waz 30

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

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int
Run Code Online (Sandbox Code Playgroud)

有关详细解答.看看C++标准中的第5/9节是什么

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

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

- 如果任一操作数的类型为long double,则另一个操作数应转换为long double.

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

- 否则,如果任一操作数是浮点数,则另一个操作数应转换为浮点数.

- 否则,应在两个操作数上执行整体促销(4.5).54)

- 然后,如果任一操作数是无符号长的,则另一个操作数应转换为无符号长整数.

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

- 否则,如果任一操作数很长,另一个操作数应转换为long.

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

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

  • ......只要另一种类型既不是"双"也不是"长双". (3认同)

leg*_*s2k 17

由于其他答案没有谈到C++ 11中的规则,所以这里是一个.从C++ 11标准(草案n3337)§5/ 9:

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

- 如果任一操作数是作用域枚举类型,则不执行任何转换; 如果另一个操作数的类型不同,则表达式格式不正确.

- 如果任一操作数的类型为long double,则另一个操作数应转换为long double.

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

- 否则,如果任一操作数是浮点数,则另一个操作数应转换为浮点数.

- 否则,应在两个操作数上执行整体促销.然后,以下规则应适用于提升的操作数:

- 如果两个操作数具有相同的类型,则不需要进一步转换.

- 否则,如果两个操作数都有有符号整数类型或两者都有无符号整数类型,则具有较小整数转换等级类型的操作数应转换为具有较大等级的操作数的类型.

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

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

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

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

  • 这些规则在 C++ 的所有版本中都是相同的,当然除了 C++11 中添加的作用域枚举之外 (2认同)

Dav*_*one 6

这个答案在很大程度上取决于@RafałDowgird的评论:

"最小操作规模是int." - 这会非常奇怪(那些有效支持char/short操作的架构呢?)这真的是在C++规范中吗?

请记住,C++标准具有非常重要的"假设"规则.请参见第1.8节:程序执行:

3)这一规定有时被称为"假设"规则,因为只要结果好像符合要求,实施可以自由地忽视标准的任何要求,只要可以从可观察的数据中确定.该计划的行为.

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

因此,对于具有超快速8位操作的理论计算机,int对算术的隐式提升可能很重要.但是,对于许多操作,您无法判断编译int器是否以a 的精度实际执行了操作,然后转换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.

这通常是加法,减法和乘法.对于除法或模数,通常不是这样.


Jam*_*nze 5

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

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

  • Stroustrup 可以推荐他喜欢的内容,但是对不需要为负数的数字使用可签名的“int”完全浪费了可用范围的 50%。我当然不是 Stroustrup,但我默认使用“unsigned”,只有当我有理由时才使用“signed”。 (3认同)
  • 一切都很好,underscore_d,直到你必须做减法的那一天。C++ 中无符号数字的主要问题是,当执行减法时,它们保持无符号状态。因此,假设您编写一个函数来查看 std::vector 是否有序。你可以写 `bool in_order(vector&lt;T&gt; vec) { for ( int i = 0; i &lt; size() - 1; ++i) { if (vec[i + 1] &lt; vec[i]) return false ; 然后你会恼火地发现它因空向量而崩溃,因为 size() - 1 返回 18446744073709551615。 (2认同)