類型轉(zhuǎn)換
在C++語法中,有幾種方式進行類型轉(zhuǎn)換:
// Example 7.19
int i; float f;
f = i; // Implicit type conversion
f = (float)i; // C-style type casting
f = float(i); // Constructor-style type casting
f = static_cast<float>(i); // C++ casting operator
這些不同的方法有完全相同的效果。使用哪種方法是一個編程風(fēng)格的問題。下邊討論下不同轉(zhuǎn)換的時間損耗。
signed與unsigned轉(zhuǎn)換
。。。
有符號與無符號整數(shù)間的轉(zhuǎn)換只是讓編譯器以不同的方式解釋整數(shù)的比特。不檢查溢出,代碼不需要額外時間。
整數(shù)大小轉(zhuǎn)換
int i; short int s;
i = s;
一個整數(shù)轉(zhuǎn)換成一個位數(shù)更長的整數(shù)時,如果是有符號的,通過擴展符號位,如果是無符號的,通過零擴展。如果是一個算術(shù)表達式的結(jié)果進行,通常需要1時鐘周期。如果從內(nèi)存讀取一個變量的值來轉(zhuǎn)換,通常不需要額外時間,如下:
。。。
將整數(shù)轉(zhuǎn)換到更小的類型僅僅是忽略高位比特,不檢查溢出。例如:
。。。
這個轉(zhuǎn)換不需要額外時間。它只是保存32位整數(shù)的低16位。
浮點精度轉(zhuǎn)換
在使用浮點寄存器棧時,float、double與long double間的轉(zhuǎn)換不需要額外時間。在使用XMM寄存器時,需要2到15時鐘周期(取決于處理器)。例子:
// Example 7.24
float a; double b;
a += b;
在這個例子中,如果使用XMM寄存器,轉(zhuǎn)換是相對低效的。a與b應(yīng)該是相同類型以避免。
整數(shù)到浮點轉(zhuǎn)換
有符號整數(shù)到float或double的轉(zhuǎn)換需要4 ~ 6時鐘周期,取決于處理器與使用的寄存器類型。無符號整數(shù)的轉(zhuǎn)換需要更長時間,除非AVX512指令集可用(AVX512DQ用于64bit無符號整數(shù))。如果沒有溢出的危險,首先把無符號整數(shù)轉(zhuǎn)換到有符號整數(shù)會更快的:
。。。
浮點到整數(shù)轉(zhuǎn)換
浮點值到整數(shù)的轉(zhuǎn)換需要非常長的時間,除非啟用SSE2或更新的指令集。通常,轉(zhuǎn)換需要50 ~ 100時鐘周期。原因是C/C++標準指定截斷,因此浮點取整模式必須改變?yōu)榻財?,再改回來?/p>
如果在代碼的關(guān)鍵部分存在浮點到整數(shù)轉(zhuǎn)換,那么對進行優(yōu)化是重要的??赡艿姆桨赣校?/p>
- 使用不同類型的變量,避免轉(zhuǎn)換。
- 將中間結(jié)果保存為浮點類型,將轉(zhuǎn)換移出最里層循環(huán)。
。。。
指針類型轉(zhuǎn)換
指針可以被轉(zhuǎn)換到另一個類型的指針。類似的,指針可以轉(zhuǎn)換到整數(shù),或者整數(shù)可以轉(zhuǎn)換到指針。整數(shù)有足夠的bit位保存指針是重要的。
這些轉(zhuǎn)換不會產(chǎn)生額外的代碼。它只是以不同的方式解釋相同比特,或者繞過語法檢查。
當然,這些轉(zhuǎn)換不安全。確保結(jié)果有效是程序員的責(zé)任。
重新解釋對象的類型
通過轉(zhuǎn)換地址類型,使編譯器將一個變量或?qū)ο螽斪隽硪粋€類型是可能的:
float x;
*(int*)&x |= 0x80000000; // Set sign bit of x
這里,語法看起來有些奇怪。x 的地址被類型轉(zhuǎn)換為一個整數(shù)指針,然后通過把x當做整數(shù)訪問。實際上制作一個指針,編譯器不產(chǎn)生任何額外的代碼真正創(chuàng)造一個指針。這個指針只是被優(yōu)化掉,結(jié)果x被處理為一個整數(shù)。但 & 操作符強制編譯器在內(nèi)存而不是寄存器里保存x。上面例子通過使用只能應(yīng)用于整數(shù)的 | 操作符設(shè)置 x 的符號位。它比x = -abs( x );
更快。
在類型轉(zhuǎn)換指針時,要小心一些風(fēng)險:
- 違反嚴格的標準C別名規(guī)則,尤其是不同類型的兩個指針不能指向相同的對象(除了char指針)。優(yōu)化編譯器可能在兩個不同的寄存器中保存浮點與整數(shù)表示。你需要檢查編譯器的行為是否就是你所期望的。使用聯(lián)合更安全。
- 如果對象被當做比其實際更大的類型對待,該技巧會無效。上面這個代碼將出錯,如果int比float使用更多比特。(在x86系統(tǒng)里,兩者都使用32比特)。
。。。
const_cast
const_cast用于去除一個指針的const限制。它有一些語法檢查,因此,比C風(fēng)格的類型轉(zhuǎn)換更安全,無需添加任何額外的代碼。例如:
。。。
static_cast
static_cast操作符做的與C形式的類型轉(zhuǎn)換相同。
reinterpret_cast
reinterpret_cast操作符用于指針轉(zhuǎn)換。與c風(fēng)格的轉(zhuǎn)換類似,但會進行一些語法檢查,不產(chǎn)生任何額外的代碼。
dynamic_cast
dynamic_cast操作符用于將一個類指針轉(zhuǎn)換為另一個類的指針。它對轉(zhuǎn)換的有效性進行運行時檢查。例如,在一個基類指針被轉(zhuǎn)換為派生類的指針時,它檢查原始指針是否真的指向派生類的一個對象。這個檢查使得dynamic_cast比簡單的類型轉(zhuǎn)換更耗時些,但也更安全。它可能捕捉到原本沒發(fā)現(xiàn)的編程錯誤。
轉(zhuǎn)換類對象
涉及類對象的轉(zhuǎn)換(而不是對象指針)是看可能的,只要程序員定義了說明如何進行這個轉(zhuǎn)換的一個構(gòu)造函數(shù)、一個重載賦值操作符或一個重載類型轉(zhuǎn)換操作符。構(gòu)造函數(shù)或重載操作符與成員函數(shù)效率相同。文章來源:http://www.zghlxwxcb.cn/news/detail-775912.html
歡迎交流文章來源地址http://www.zghlxwxcb.cn/news/detail-775912.html
到了這里,關(guān)于C++性能優(yōu)化筆記-6-C++元素的效率差異-7-類型轉(zhuǎn)換的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!