下面的代码调用gcc中clz/ctz的内置函数,在其他系统上,它有c版本。显然,如果系统有内置的clz/ctz指令,比如x86和arm,那么c版本就有点次优了。

#ifdef __GNUC__
#define clz(x) __builtin_clz(x)
#define ctz(x) __builtin_ctz(x)
#else
static uint32_t ALWAYS_INLINE popcnt( uint32_t x )
{
    x -= ((x >> 1) & 0x55555555);
    x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
    x = (((x >> 4) + x) & 0x0f0f0f0f);
    x += (x >> 8);
    x += (x >> 16);
    return x & 0x0000003f;
}
static uint32_t ALWAYS_INLINE clz( uint32_t x )
{
    x |= (x >> 1);
    x |= (x >> 2);
    x |= (x >> 4);
    x |= (x >> 8);
    x |= (x >> 16);
    return 32 - popcnt(x);
}
static uint32_t ALWAYS_INLINE ctz( uint32_t x )
{
    return popcnt((x & -x) - 1);
}

#endif

我需要调用哪些函数,需要包含哪些头,等等来为msvc添加适当的ifdef?我已经看了this page,但我不完全确定pragma是用来做什么的(它是必需的吗?)以及它对msvc版本编译要求的限制。作为一个并不真正使用msvc的人,我也不知道这些内部函数在其他架构上是否有c等价物,或者我是否必须定义它们。

最佳答案

从sh0dan代码跳转过来,应该像这样更正实现:

#ifdef _MSC_VER
#include <intrin.h>

uint32_t __inline ctz( uint32_t value )
{
    DWORD trailing_zero = 0;

    if ( _BitScanForward( &trailing_zero, value ) )
    {
        return trailing_zero;
    }
    else
    {
        // This is undefined, I better choose 32 than 0
        return 32;
    }
}

uint32_t __inline clz( uint32_t value )
{
    DWORD leading_zero = 0;

    if ( _BitScanReverse( &leading_zero, value ) )
    {
       return 31 - leading_zero;
    }
    else
    {
         // Same remarks as above
         return 32;
    }
}
#endif

如代码中所述,如果值为0,则ctz和clz都是未定义的。在我们的抽象中,我们将__builtin_clz(value)固定为(value?__builtin_clz(value):32),但这是一个选择

关于c - 如何使用MSVC内部函数来获得与此GCC代码等效的内容?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/355967/

10-08 22:57