簡體   English   中英

驗證C / C ++簽名的右移是特定編譯器的算術運算?

[英]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_arithmetictrue ,那么每個編譯器都值得使用它將消除整個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM