编译时检查右移是否是对有符号类型的算术

我想知道在编译时操作有符号类型(例如,是否
-2 >> 1
-1
)时,检查右移是否为算术的最便携方法是什么。 我的想法是在编译时以某种方式检查它并能够检测到这一点,因此我可以编译该函数的不同版本(取决于运算符
>>
是否真的是算术移位)。 通过阅读主题 验证C / C ++签名的右移是特定编译器的算术运算?我想到了初始化旗帜的想法
static const bool is_arithmetic_rs = (((signed int)-1)>>1) == ((signed int)-1));
并在运行时测试它像这样:
if (is_arithmetic_rs) {
  // some fast algorithm using arithmetic right shifts (using >> operator)
} else {
  // the same algorithm without arithmetic right shifts (much slower)
}
但是,我希望每次都尽可能避免这种分支。为简单起见,我们假设我想实现一个可移动的算术右移;如果每次调用函数时都必须检查这个,这会对性能造成巨大影响,所以我想在编译时这样做,如果可能的话。 如果没有可移植的方法来进行此检查,是否有办法通过检查尽力而为的方式来完成此操作,例如使用ifdef检查特定的编译器/平台?     
已邀请:
通过使用预处理时间测试可以避免分支
#if ((-1)>>1) == (-1))
...
#else
...
#endif
    
执行此类检查的最佳方法是例如GNU autotools: 在目标平台上编译一个小程序并测试会发生什么 在头文件中设置适当的
#define
在源文件中包含该头文件 (可选)使用适当定义的宏,这样就不会为每个小东西用
#ifdef
指令混乱代码。 编译您的主项目 这样你就不必创建具有支持功能的表以及每个硬件平台和操作系统的各种怪癖 - 更不用说它们的组合了。但是,如果不在目标上构建代码,则必须使用预先提供的目标表/功能列表替换第一步。 您可能应该看看广泛使用的构建系统,例如GNU autotools或CMake,以便重用现有的宏和特定于平台的信息,并避免创建自己的构建系统,从而重新发明轮子。 BTW,现在任何体面的编译器都应该使用常量表达式优化出简单的测试,因此在必要时使用运行时测试 - 可能通过宏 - 不应该对性能造成太大影响。您应该测试并分析您的代码以找出答案。     
真的更多的是评论而不是答案(但显然我不是很有信誉) 这里的几个答案使用预处理器检查
#if ((-1)>>1) == (-1))
就个人而言,我不相信预处理器告诉我编译器生成什么样的代码。     
您是否确实已经验证过您的编译器在可用时不会将除法优化为算术移位? 否则我认为你可以使用模板。
template <bool B>
void do_work();

template <>
void do_work<true>()
{
    // Do stuff with H/W.
}

template <>
void do_work<false>()
{
    // Do slow stuff with S/W.
}

do_work<(-2 >> 1) == -1>();
然后使用内联函数更漂亮:
inline real_do_work()
{
    do_work<(-2 >> 1) == -1>();
}
    
试试这个:
#define SAR(x,y) ((x)>=0) ? ((x)>>(y)) : (~(~(x)>>(y)))
假设CPU是理智的,一个好的编译器会优化它到
((x)>>(y))
。 欢迎反馈哪些编译器是好的。     
灵感来自朱塞佩和R ..的答案:
#if -2 >> 1 == -1
#define rshift_ar(X, Y) ((X) >> (Y))
#elif ~(~(-2) >> 1) == -1
#define rshift_ar(X, Y) ((X) >= 0 ? (X) >> (Y) : ~(~(X) >> (Y)))
#else
#error "unsupported shifting semantics"
#endif
    
所有这些预处理器魔法对于任何体面的编译器都是无用的。您是否验证上面给出的代码确实在其输出中生成了分支?我非常怀疑它,因为
static const bool
会被评估为编译时间常数,因此编译器将消除你的
if (is_arithmetic_rs)
部分,其中任何高于
-O1
。另见我的答案。 此外,我怀疑预处理器的输出保证与编译器的输出相同,特别是在具有不同移位的平台之间进行交叉编译时。     

要回复问题请先登录注册