验证C / C ++签署右移是算术特定的编译器?(Verifying that C / C++ si

2019-08-22 10:27发布

根据C / C ++标准(见本链接) ,>>操作符在C和C ++不一定是带符号的数字算术移位。 它是由编译器实现是否0(逻辑)或符号位(算术)被移位的位右移。

将这段代码函数断言(失败)在编译时间实现符号整数逻辑右移编译器?

#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 );

Answer 1:

在我看来很好! 还可以设置编译器以发射组件文件(或加载在调试已编译的程序),并期待在该操作码它发射用于signed int i; i >> 1; signed int i; i >> 1; ,但是这不是自动喜欢你的解决方案。

如果你发现没有实现有符号数的算术右移一个编译器,我想听到它。



Answer 2:

为什么断言? 如果你的编译器的移位运算符不符合你的需求,你可以优雅地弥补由结果符号扩展的情况。 此外,有时运行时间是不够好。 毕竟,编译器的优化可以让编译时出的运行时间:

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.");


Answer 3:

从你的各种评论,请您谈一下使用这个跨平台的。 确保你的编译器保证,当他们编译的平台,他们的编译时运营商将行为相同,运行时间的。

不同行为的一个实例可以用浮点数被发现。 是你的编译器做它的常量表达式运算在单,双或扩展精度,如果你铸造回诠释? 如

constexpr int a = 41;
constexpr int b = (a / 7.5);

我的意思是,你应该确保你的编译器保证期间,当你遇到了许多不同的架构工作运行时编译时相同的行为。

这是完全有可能的编译器可能会在内部符号扩展,但不会产生对目标的预期操作码(S)。 可以肯定的唯一方法是在运行时测试或看汇编输出。

这不是世界末日来看看汇编输出......有多少种不同的平台有哪些? 既然是这样的表现,关键只是做的看着1-3行汇编输出为5层不同的体系结构“工作”。 这是不是如果你有通过整个组件输出潜水(一般!)找到你行。 这是非常,非常容易做到的。



文章来源: Verifying that C / C++ signed right shift is arithmetic for a particular compiler?
标签: c++ c math signed