c++ - __builtin_ctz(0)或__builtin_clz(0)有多不确定?

标签 c++ undefined-behavior constexpr c++14 bit-manipulation

背景

长期以来,gcc has been providing有许多内置的位旋转功能,尤其是尾随和前导0位的数量(也适用于long unsignedlong long unsigned,其后缀为lll):

— Built-in Function: int __builtin_clz (unsigned int x)

Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.

— Built-in Function: int __builtin_ctz (unsigned int x)

Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.



但是,在我测试的每个在线(免责声明:仅x64)编译器上,结果是clz(0)ctz(0)都返回基础内置类型的位数,例如
#include <iostream>
#include <limits>

int main()
{
    // prints 32 32 32 on most systems
    std::cout << std::numeric_limits<unsigned>::digits << " " << __builtin_ctz(0) << " " << __builtin_clz(0);    
}

Live Example

尝试的解决方法
std=c++1y模式下的最新Clang SVN干线使所有这些函数都放松了C++ 14 constexpr,这使它们可以在SFINAE表达式中用于3个ctz / clz内置unsignedunsigned longunsigned long long的包装器函数模板。
template<class T> // wrapper class specialized for u, ul, ull (not shown)
constexpr int ctznz(T x) { return wrapper_class_around_builtin_ctz<T>()(x); }

// overload for platforms where ctznz returns size of underlying type
template<class T>
constexpr auto ctz(T x) 
-> typename std::enable_if<ctznz(0) == std::numeric_limits<T>::digits, int>::type
{ return ctznz(x); }

// overload for platforms where ctznz does something else
template<class T>
constexpr auto ctz(T x) 
-> typename std::enable_if<ctznz(0) != std::numeric_limits<T>::digits, int>::type
{ return x ? ctznz(x) : std::numeric_limits<T>::digits; }

这种攻击的好处在于,为ctz(0)提供所需结果的平台可以省略测试x==0的额外条件(这似乎是微优化的,但是当您已经达到内置位纠缠功能的水平时,它会可以有很大的不同)

问题

内置函数clz(0)ctz(0)的系列如何不确定?
  • 他们可以抛出std::invalid_argument异常吗?
  • for x64,对于当前的gcc发行版,它们是否会返回底层字体的大小?
  • 与ARM / x86平台有什么不同(我无权对其进行测试)?
  • 是上述SFINAE技巧是一种很好的方法来分隔此类平台吗?
  • 最佳答案

    不幸的是,甚至x86-64的实现也可能有所不同-与Intel的instruction set referenceBSFBSR相比,源操作数值为(0),目标未定义,并设置了ZF(零标志)。因此,这种行为在微体系结构或AMD和Intel之间可能不一致。 (我相信AMD会将目的地保持不变。)

    较新的LZCNTTZCNT指令并非无处不在。两者仅在Haswell架构(适用于Intel)上存在。

    关于c++ - __builtin_ctz(0)或__builtin_clz(0)有多不确定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64252652/

    相关文章:

    c++ - boost::in_place 将参数作为 const refs

    C++ 枚举类 : Cast to non existing entry

    c++ - 为什么这不是一个常量表达式?

    c++ - 'half' 不是 'Eigen' 的成员

    c++ - 如何实例化架构对象?

    c++ - 为什么这个智能指针在它的目标应该被删除时却给出了正确的结果?

    c++ - 如何在 GCC 中启用反斜杠支持?

    c++ - Constexpr变量不是编译时值吗?

    c++ - 为什么我不能在 C++11 中使用 constexpr 指针作为模板参数?

    c++ - 有条件地在类中创建成员