问题
I've got a little C++ project that was developed for Win32 and I want to port it to OSX. The code uses functions like _bittest
and _bittest64
but I haven't found same functions in the XCode header files.
What could be an alternative for these functions? May be there are good working polyfills. The project is a legacy indeed, no extra performance is required at the moment.
回答1:
The _bittest and _bittest64 symbols are compiler intrinsics, that emit Bit-test instructions, specifically x86 bt, to examine the value of a bit at a zero-based index.
With a memory operand, bt
has crazy-CISC bitstring behaviour where the bit index can go outside the dword/qword of memory selected by the addressing mode. This is slow and why compilers will load the operand into a register first. But this is what the MSVC intrinsic is for. Otherwise it wouldn't need to be an intrinsic.
The following C++ matches the behaviour of register-arg version of the bt
instruction, wrapping the shift count at the register width, i.e. effectively looking only at the low bits. (This matches the MSVC intrinsic if b
is <32 or <64.) See the updated code and comments for discussion of how to implement the MSVC semantics which let it access outside the pointed-to long
or long long
.
Also beware that long
is a 32-bit type in the x64 Windows ABI, but a 64-bit type in the x86-64 System V ABI (which you're using on OS X, unless you build obsolete 32-bit code). You may want to change your code to int32_t
or uint32_t
to avoid leaving unused bits in each long
, depending on how you're using it.
inline
unsigned char bittest(long const *a, long b)
{
auto const value{ *a };
auto const mask{ 1L << (b&31) };
auto const masked_value{ value & mask };
return unsigned char{ masked_value != 0 };
}
inline
unsigned char bittest64(long long const *a, long long b)
{
auto const value{ *a };
auto const mask{ 1LL << (b&63) };
auto const masked_value{ value & mask };
return unsigned char{ masked_value != 0 };
}
I'm not aware of any GCC or Clang intrinsics with identical functionality. If needed, you could resort to emitting assembly instructions from the function implementations instead, but bt
with a memory operand is slow so it's normally best to implement in pure C++ and let the compiler do a good job.
Update:
After discussing the code emitted from the intrinsics, it has become clear, that the previously proposed replacement code only covers part of the functionality. In particular, the intrinsics allow indexing bits outside the memory occupied by *a
. The following implementations account for that as well.
inline
unsigned char bittest(std::int32_t const *a, std::int32_t b)
{
auto const bits{ reinterpret_cast<unsigned char const*>(a) };
auto const value{ bits[b >> 3] };
auto const mask{ (unsigned char)(1 << (b & 7)) };
return (value & mask) != 0;
}
inline
unsigned char bittest64(std::int64_t const *a, std::int64_t b)
{
auto const bits{ reinterpret_cast<unsigned char const*>(a) };
auto const value{ bits[b >> 3] };
auto const mask{ (unsigned char)(1 << (b & 7)) };
return (value & mask) != 0;
}
来源:https://stackoverflow.com/questions/50832505/xcode-and-bittest-function