[英]Verifying that C / C++ signed right shift is arithmetic for a particular compiler?
根據C / C ++標准(參見此鏈接) ,C和C ++中的>>運算符不一定是有符號數的算術移位。 由於位向右移位,所以由編譯器實現是0(邏輯)還是符號位(算術)移入。
對於為有符號整數實現邏輯右移的編譯器,此代碼是否會在編譯時對ASSERT(fail)起作用?
#define COMPILE_TIME_ASSERT(EXP) \
typedef int CompileTimeAssertType##__LINE__[(EXP) ? 1 : -1]
#define RIGHT_SHIFT_IS_ARITHMETIC \
( (((signed int)-1)>>1) == ((signed int)-1) )
// SHR must be arithmetic to use this code
COMPILE_TIME_ASSERT( RIGHT_SHIFT_IS_ARITHMETIC );
在我看來很好! 您還可以將編譯器設置為發出一個匯編文件(或在調試器中加載已編譯的程序),並查看它為signed int i; i >> 1;
發出的操作碼signed int i; i >> 1;
signed int i; i >> 1;
,但這不像你的解決方案那樣自動化。
如果您發現編譯器沒有實現有符號數的算術右移,我想聽聽它。
為什么斷言? 如果編譯器的移位運算符不適合您的需要,您可以通過對結果進行符號擴展來優雅地糾正這種情況。 此外,有時運行時間足夠好。 畢竟,編譯器的優化器可以使編譯時間超出運行時間:
template <typename Number>
inline Number shift_logical_right(Number value, size_t bits)
{
static const bool shift_is_arithmetic = (Number(-1) >> 1) == Number(-1);
const bool negative = value < 0;
value >>= bits;
if (!shift_is_arithmetic && negative) // sign extend
value |= -(Number(1) << (sizeof(Number) * 8 - bits));
}
static const bool
可以在編譯時進行計算,因此如果保證shift_is_arithmetic
為true
,那么每個編譯器都值得使用它將消除整個if
子句並將const bool negative
構造為死代碼。
注意:代碼是根據Mono的encode_sleb128
函數改編的: 這里 。
更新
如果你真的想在沒有算術移位的機器上中止編譯,你最好還是不要依賴預處理器。 您可以使用static_assert
(或BOOST_STATIC_ASSERT
):
static_assert((Number(-1) >> 1) == Number(-1), "Arithmetic shift unsupported.");
從您的各種評論,您談到使用這個跨平台。 確保編譯器保證在編譯平台時,編譯時運算符的行為與運行時運算符相同。
可以使用浮點數找到不同行為的示例。 如果要轉換回int,您的編譯器是以單精度,雙精度還是擴展精度執行常量表達式數學運算? 如
constexpr int a = 41;
constexpr int b = (a / 7.5);
我所說的是,當你在這么多不同的架構上工作時,你應該確保你的編譯器在運行時保證與編譯時相同的行為。
編譯器完全有可能在內部進行符號擴展,但不會在目標上生成預期的操作碼。 唯一可以確定的方法是在運行時測試或查看匯編輸出。
看看裝配輸出並不是世界末日......有多少個不同的平台? 由於這對性能至關重要,所以只需要為5種不同的架構查看1-3行匯編輸出的“工作”。 這並不是說您必須潛入整個裝配輸出(通常!)才能找到您的生產線。 這非常非常容易。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.