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

eol*_*old 5 c c++ portability bit-manipulation compile-time

我想知道什么是检查签署类型进行操作时右移是算术的最简便的方式(例如:是否-2 >> 1-1)在编译时.

我的想法是在编译时以某种方式检查它并能够检测到这一点,因此我可以编译该函数的不同版本(取决于运算符>>是否真的是算术移位).

通过阅读主题 验证C/C++签名的右移是特定编译器的算术吗?我想到了初始化旗帜的想法

static const bool is_arithmetic_rs = (((signed int)-1)>>1) == ((signed int)-1));
Run Code Online (Sandbox Code Playgroud)

并在运行时测试它像这样:

if (is_arithmetic_rs) {
  // some fast algorithm using arithmetic right shifts (using >> operator)
} else {
  // the same algorithm without arithmetic right shifts (much slower)
}
Run Code Online (Sandbox Code Playgroud)

但是,我希望每次都尽可能避免这种分支.为简单起见,我们假设我想实现一个可移动的算术右移; 如果每次调用函数时都必须检查这个,这会对性能造成巨大影响,所以我想在编译时这样做,如果可能的话.

如果没有可行的方法来进行此检查,是否有办法通过检查尽力而为的方式来完成此操作,例如使用ifdef检查特定的编译器/平台?

thk*_*ala 8

执行此类检查的最佳方法是例如GNU autotools:

  • 在目标平台上编译一个小程序并测试会发生什么

  • #define在头文件中设置适当的

  • 在源文件中包含该头文件

  • (可选)使用适当定义的宏,这样就不会#ifdef为每个小东西的指令混乱代码.

  • 编译您的主项目

这样你就不必创建具有支持功能的表以及每个硬件平台和操作系统的各种怪癖 - 更不用说它们的组合.但是,如果不在目标上构建代码,必须使用预先提供的目标表/功能列表替换第一步.

您可能应该查看广泛使用的构建系统,例如GNU autotools或CMake,以便重用现有的宏和特定于平台的信息,并避免创建自己的构建系统,从而重新发明轮子.

BTW,现在任何体面的编译器都应该使用常量表达式优化出简单的测试,因此在必要时使用运行时测试 - 可能通过宏 - 不应该对性能造成太大影响.您应该测试并分析您的代码以找出答案.


Giu*_*ini 7

通过使用预处理时间测试可以避免分支

#if ((-1)>>1) == (-1))
...
#else
...
#endif
Run Code Online (Sandbox Code Playgroud)

  • 预处理器是否保证提供与编译器完全相同的结果?我非常怀疑它,特别是在交叉编译时. (4认同)

小智 5

确实更多的是评论而不是答案(但显然我没有信誉)

这里的几个答案使用预处理器检查,例如

#if ((-1)>>1) == (-1))
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我不相信预处理器会告诉我编译器生成什么样的代码。