以下代码在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等价物,或者在#defining它们时是否还需要#ifdef x86 / x86_64。
答案 0 :(得分:19)
从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)
,但它是一个选择
答案 1 :(得分:1)
答案 2 :(得分:0)
我在韩国网站https://torbjorn.tistory.com/317中找到了它
在msvc编译器中,可以使用__lzcnt(unsigned int)
替换gcc编译器中的__builtin_clz(unsigned int)
。
答案 3 :(得分:0)
int __builtin_ctz (unsigned int x) 在 MSVC 中的等效函数是 unsigned int _tzcnt_u32 (unsigned int a) 对于 32 位 em> 整数并返回尾随零的计数。对于 64 位,使用 unsigned __int64 _tzcnt_u64 (unsigned __int64 a) 1。
int __builtin_clz (unsigned int x) 在 MSVC 中的等效函数是 unsigned int _lzcnt_u32 (unsigned int a) 对于 32 位 em> 整数并返回前导零的计数。对于 64 位,使用 unsigned __int64 _lzcnt_u64 (unsigned __int64 a) 2
C++ 头文件:immintrin.h
答案 4 :(得分:-3)
有两个内在函数“_BitScanForward”和“_BitScanReverse”,它们适用于MSVC。包括。功能是:
#ifdef _MSC_VER
#include <intrin.h>
static uint32_t __inline ctz( uint32_t x )
{
int r = 0;
_BitScanReverse(&r, x);
return r;
}
static uint32_t __inline clz( uint32_t x )
{
int r = 0;
_BitScanForward(&r, x);
return r;
}
#endif
有等效的64位版本“_BitScanForward64”和“_BitScanReverse64”。
在这里阅读更多内容:
答案 5 :(得分:-3)
在linux和windows(x86)上测试:
#ifdef WIN32
#include <intrin.h>
static uint32_t __inline __builtin_clz(uint32_t x) {
unsigned long r = 0;
_BitScanReverse(&r, x);
return (31-r);
}
#endif
uint32_t clz64(const uint64_t x)
{
uint32_t u32 = (x >> 32);
uint32_t result = u32 ? __builtin_clz(u32) : 32;
if (result == 32) {
u32 = x & 0xFFFFFFFFUL;
result += (u32 ? __builtin_clz(u32) : 32);
}
return result;
}