讀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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章