读C++标准系列 - 5.6~5.15 双目运算符(算术运算)

返回目录

首先,双目运算符在运算之前,会对操作数进行类型提升,以使两者的类型相同。同时,该类型也将会是最后结果的类型(5-10)
1、如果任何一个操作数是long double、double或者float,那么两者都会提升到该类型
2、否则,会对操作数进行integral promotion,在此之后
3、如果两者都是有符号或者无符号,以rank大的类型为准。否则
4、如果无符号类型的rank大于等于有符号类型,则以无符号类型为准。否则
5、如果有符号类型能表达无符号类型所有的数值,则以有符号类型为准。否则
6、转换成该有符号类型对应的无符号类型
例如:

struct Dummy {};
void Fun(const Dummy &);

int main()
{
    Fun(10.0l+10.0); //1
    Fun(10.0+10.0f); //1
    Fun(10.0f+10LL); //1
    Fun(10L+10); //3
    Fun(10U+10); //4
    Fun(10LL+10U); //5
    Fun(10L+10U); //6
}

换言之,任何双目运算的结果不可能是char,short或者相应的无符号类型,因为integral promotion至少会将整型类型提升到int。

其次,对于无符号整数而言,所有的运算都是在模2n的数域上进行的(n是相应类型的位数)(3.9.1-4)

另外标准允许,对涉及浮点的运算,在内部使用更高的精度(譬如,Intel CPU中用于浮点计算的寄存器都是80位的)

5.6 * / %
三者分别表示乘法,除法和取余。前两者允许浮点、整型和枚举操作数。后者只允许整型和枚举操作数
/和%要求除数不能为0,否则会导致未定义的行为。

下面的等式在b不为0的时候恒成立
(a/b)*b+a%b=a
在Intel架构的CPU上,鉴于除法运算比较慢,当除数是常数时,编译器可以将除法优化成乘法,从而大大提高效率。
而取余操作无法直接优化成乘法,所以编译器有时会利用上面的公式先将a%b转化成a-(a/b)*b,再进行计算。

如果被除数和除数都是非负数,那么余数也是非负的;否则,结果是实现相关的。
比如说:
5%3必然等于2,而不会等于-1
(-5)%3和5%(-3)的结果则随编译器的不同而不同。不过在VC和GCC中,余数的符号都是由被除数决定的,所以结果都是-2和2
注:标准倾向于建议使用rounded toward zero的算法来计算商。这和VC&GCC采用的算法是一致的。

5.7 + -
没什么好说的 :-)

5.8 << >>
首先,移位的次数不能为负或者超过被移位操作数的位数,否则行为是未定义的,比如说1<<32。即使是1>>32,虽然理论上不会溢出,但同样会导致未定义的行为

左移E1<<E2,在语义等价于下面的操作:把E1看成无符号整数,假设该整数类型有n位,那么结果是
(E1*2E2)%2n

右移E1>>E2,当E1是无符号整型或者E1的值非负,等价于E1/2E2。如果E1<0,那么结果是实现相关的。
因此一般来说,E1>>E2的结果和E1/2E2未必相同。比如在VC和GCC中,(-5)/4=-1,而(-5)>>2=-2。所以当你想优化除法的时候,不能想当然的用移位来代替。大多数现代编译器都能够帮你完成这一优化,因此程序员就不必画蛇添足了。

5.9~5.10 < > == !=
注意,浮点数最好不要直接进行比较,因为它的表达是不精确的。可以设一个误差限再比较

5.11~5.13 & ^ |
没什么好说的,用于位运算

5.14~5.15 && ||
短路算法,两边的表达式会隐式转换成bool。
需要注意的是,
如果第二个表达式需要被计算,那么在运算之前,第一个表达式的所有运算和副作用必须首先完成。
所以,i++ || i++的行为是确定的
但是,表达式中产生的临时对象要到整个&&或者||表达式都计算完成之后才会析构。比如说:

#include <iostream>
using namespace std;

struct A1
{
    A1() {cout<<"A1 ctor"<<endl;}
    ~A1() {cout<<"A1 dtor"<<endl;}
    operator bool() const {return false;}
};
struct A2
{
    A2() {cout<<"A2 ctor"<<endl;}
    ~A2() {cout<<"A2 dtor"<<endl;}
    operator bool() const {return true;}
};

int main()
{
    if (A1() || A2()) ;
    return 0;
}
发布了40 篇原创文章 · 获赞 5 · 访问量 21万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章