提问人:Matt Montag 提问时间:4/6/2011 更新时间:7/14/2021 访问量:133012
C++ 运算符中的隐式类型转换规则
Implicit type conversion rules in C++ operators
问:
我想更好地了解何时应该投掷。C++ 中加法、乘法等时的隐式类型转换规则是什么?例如
int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?
等等。。。
表达式是否始终被评估为更精确的类型?Java 的规则是否不同? 如果我对这个问题的措辞不准确,请纠正我。
答:
涉及结果的算术运算。float
float
int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int
有关更多详细信息,请回答。看看 C++ 标准中的 §5/9 部分是怎么说的
许多二进制运算符,期望 算术或枚举的操作数 类型原因转换和产量 结果类型与此类似。这 目的是产生一个通用类型,这也是结果的类型。
这种模式称为通常的 算术转换,即 定义如下:
— 如果任一操作数的类型为 long 双倍,另一个应转换 到长双。
— 否则,如果任一 操作数是双倍的,另一个应该是 转换为双精度。
— 否则,如果 任一操作数为浮点数,另一方为浮数 应转换为浮点数。
— 否则,积分促销 (4.5) 应在两者上执行 操作数.54)
— 然后,如果任一操作数 未签名的,另一个应 转换为无符号长整型。
— 否则,如果一个操作数是长 int 和其他无符号 int,则 如果一个长整型 int 可以表示所有 无符号 int 的值, unsigned int 应转换为 长整数;否则两个操作数 应转换为无符号长整型 整数。
— 否则,如果任一操作数是 long,另一个应转换为 长。
— 否则,如果任一操作数 未签名的,另一个应 转换为无符号。
[注意:否则,唯一剩下的情况是 两个操作数都是 int ]
评论
double
long double
long long
unsigned long
float
int
double
当两个部分不属于同一类型时,表达式的类型将转换为两个部分中最大的类型。这里的问题是要了解哪个比另一个大(它与字节大小无关)。
在涉及实数和整数的表达式中,整数将被提升为实数。例如,在 int + float 中,表达式的类型为 float。
另一个区别与类型的功能有关。例如,涉及 int 和 long int 的表达式将产生 long int 类型的结果。
评论
long
float
long
float
整个第 4 章都谈到了转换,但我认为您应该对这些最感兴趣:
4.5 积分促销 [conv.prom]
char、signed char、unsigned char、short int 或 unsigned short 类型的右值
如果 int 可以表示源类型的所有值,则 int 可以转换为 int 类型的右值;在其他
方面,源右值可以转换为无符号 int 类型的右值。 wchar_t 型 (3.9.1) 或枚举类型 (7.2) 的右值可以转换为以下第一种
类型的右值,这些类型可以表示其基础类型的所有值:int、unsigned int、
long 或 unsigned long。
如果 int 可以表示位域的所有
值,则整数位域 (9.6) 的右值可以转换为 int 类型的右值;否则,如果 unsigned int 可以重新
发送位字段的所有值,则可以将其转换为 unsigned int。如果位场还较大,则不对其应用积分提升。如果
位字段具有枚举类型,则出于升级目的,将其视为该类型的任何其他值。
bool 类型的右值可以转换为 int 类型的右值,false 变为零,true
变为 1。
这些转化称为整体促销。
4.6 浮点提升 [conv.fpprom]
float 类型的右值可以转换为 double 类型的右值。该值保持不变。
这种转换称为浮点提升。
因此,所有涉及 float 的转换 - 结果都是 float。
只有涉及两个 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
在所有表达式中,在执行操作之前,将 提升为 a。操作的结果是 .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>
评论
char
char + char
char
char
int
CHAR_MAX
((int) 4) - ((unsigned int) 5)
4294967295
如果排除无符号类型,则有一个有序的 层次结构:有符号 char、short、int、long、long、long、float、 双倍,长双倍。首先,在 int 之前的任何内容 上面将转换为 int。然后,在二进制操作中, 排名较低的类型将转换为排名较高的类型,并且 结果将是较高的类型。(您会注意到,从 层次结构,任何时候浮点和整型类型是 涉及时,整型将转换为浮点型 点类型。
unsigned 使事情变得有点复杂:它扰乱了排名,并且 排名的部分内容将实现定义。以 这样,最好不要将有符号和无符号混用在同一个 表达。(大多数 C++ 专家似乎避免使用无符号,除非 涉及按位运算。至少,是什么 Stroustrup推荐。
评论
int
unsigned
signed
bool in_order(vector<T> vec) { for ( int i = 0; i < size() - 1; ++i) { if (vec[i + 1] < vec[i]) return false; } return true;
这个答案很大程度上是针对 @Rafa łDowgird 的评论:
“操作的最小大小是 int。” - 这会很奇怪 (有效支持 char/short 的架构呢? 操作?这真的在 C++ 规范中吗?
请记住,C++ 标准具有非常重要的“假设”规则。请参见第 1.8 节:程序执行:
3) 这一规定有时被称为“假设”规则,因为 实施可以自由地无视标准的任何要求 只要结果是好像已经遵守了要求,就 从程序的可观察行为可以确定。
编译器不能将大小设置为 8 位,即使它是最快的,因为标准要求最小值为 16 位。int
int
因此,对于具有超快 8 位运算的理论计算机,隐式提升算术可能很重要。但是,对于许多操作,您无法判断编译器是否实际上以 an 的精度执行了操作,然后转换为 a 以存储在变量中,或者这些操作是否一直在 char 中完成。int
int
char
例如,考虑 ,其中加法会溢出(假设每个值为 200)。如果你提升到 ,你会得到 600,然后它被隐式下放到 ,这将包装模 256,从而得到 88 的最终结果。如果你没有进行这样的促销,你就必须在前两个添加之间换行,这将使问题从 到 ,即 344,减少到 88。换言之,程序不知道其中的区别,因此,如果操作数的排名低于 ,编译器可以自由地忽略执行中间操作的命令。unsigned char = unsigned char + unsigned char + unsigned char
int
unsigned char
200 + 200 + 200
144 + 200
int
int
一般来说,加法、减法和乘法都是如此。一般来说,除法或模量不是这样。
由于其他答案没有讨论 C++11 中的规则,所以这里有一个。摘自 C++11 标准(草案 n3337)§5/9(强调差异):
这种模式称为通常的算术转换,其定义如下:
— 如果任一操作数为作用域枚举类型,则不执行任何转换;如果另一个操作数没有相同的类型,则表达式格式不正确。
— 如果其中一个操作数的类型为 long double,则另一个操作数应转换为 long double。
— 否则,如果其中一个操作数是双精度的,则另一个操作数应转换为双精度。
— 否则,如果其中一个操作数是浮点数,则另一个操作数应转换为浮点数。
— 否则,应在两个操作数上执行整体提升。然后,以下规则应应用于提升的操作数:
— 如果两个操作数具有相同的类型,则无需进一步转换。
— 否则,如果两个操作数都有带符号整数类型,或者两者都有无符号整数类型, 类型为较小整数转换秩的操作数应转换为 操作数具有更高的等级。
— 否则,如果具有无符号整数类型的操作数的秩大于或等于 另一个操作数类型的 rank,带符号整数类型的操作数应转换为 具有无符号整数类型的操作数的类型。
— 否则,如果具有有符号整数类型的操作数类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数应 转换为具有有符号整数类型的操作数类型。
— 否则,两个操作数都应转换为对应于 具有有符号整数类型的操作数的类型。
有关经常更新的列表,请参阅此处。
评论
我对问题的解决方案得到了 WA(错误答案),然后我更改了其中一个,它给了 AC(接受)。以前,我试图做,在我纠正它之后。我想出的谷歌搜索,int
long long int
long long int += int * int
long long int += long long int * int
1. 算术转换
类型转换的条件:
转换--->满足条件
任一操作数均为 long double 类型。---> 其他操作数转换为类型 long double。
不满足上述条件,并且任一操作数的类型为 double。---> 其他操作数转换为类型 double。
不满足上述条件,并且任一操作数的类型为 float。---> 其他操作数转换为浮点型。
不满足上述条件(所有操作数都不是浮点类型)。---> 对操作数执行整数提升,如下所示:
- 如果其中一个操作数的类型为 unsigned long,则另一个操作数将转换为 unsigned long 类型。
- 如果不满足上述条件,并且如果其中一个操作数的类型为 long,而另一个操作数的类型为 unsigned int,则两个操作数都将转换为 unsigned long 类型。
- 如果不满足上述两个条件,并且其中一个操作数为 long 类型,则其他操作数将转换为 long 类型。
- 如果不满足上述三个条件,并且其中一个操作数的类型为 unsigned int,则另一个操作数将转换为 unsigned int 类型。
- 如果上述条件均不满足,则两个操作数都将转换为 int 类型。
2 .整数转换规则
- 整数促销:
小于 int 的整数类型在对它们执行操作时被提升。如果原始类型的所有值都可以表示为 int,则较小类型的值将转换为 int;否则,它将转换为无符号 int。整数升级作为对某些参数表达式的通常算术转换的一部分应用;一元 +、- 和 ~ 运算符的操作数;以及轮班操作员的操作数。
整数转换排名:
- 任何两个有符号整数类型都不应具有相同的等级,即使它们具有相同的表示形式。
- 有符号整数类型的秩应大于任何精度较低的有符号整数类型的秩。
- 的等级应大于 的等级 ,而 的等级应大于 的等级 ,该等级应大于 的等级。
long long int
long int
int
short int
signed char
- 任何无符号整数类型的排名都应等于相应有符号整数类型的排名(如果有)。
- 任何标准整数类型的秩都应大于任何具有相同宽度的扩展整数类型的秩。
- 的等级应等于 和 的等级。
char
signed char
unsigned char
- 任何扩展有符号整数类型相对于具有相同精度的扩展有符号整数类型的排名都是由实现定义的,但仍受用于确定整数转换排名的其他规则的约束。
- 对于所有整数类型 T1、T2 和 T3,如果 T1 的排名高于 T2,而 T2 的排名高于 T3,则 T1 的排名高于 T3。
通常的算术转换:
- 如果两个操作数具有相同的类型,则无需进一步转换。
- 如果两个操作数都属于相同的整数类型(有符号或无符号),则具有较小整数转换等级类型的操作数将转换为具有较高等级的操作数类型。
- 如果具有无符号整数类型的操作数的秩大于或等于其他操作数类型的秩,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型。
- 如果具有有符号整数类型的操作数类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数将转换为具有有符号整数类型的操作数类型。
- 否则,两个操作数都将转换为无符号整数类型,该类型对应于具有有符号整数类型的操作数类型。特定运算可以添加或修改通常算术运算的语义。
警告!
转换从左到右进行。
试试这个:
int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0
评论
j + i * k
上一个:如何在PHP中将数组转换为对象?
下一个:在 Java 中转换变量
评论
^