对于 32 位块类型,这里有两种可能的实现方式:
#include <cstdint>
uint32_t bit_assign_v1(uint32_t block, uint8_t bit_index, bool x)
{
uint32_t mask = uint32_t { 1 } << bit_index;
return (block & ~mask) | (((uint32_t) x) << bit_index);
}
uint32_t bit_assign_v2(uint32_t block, uint8_t bit_index, bool x)
{
uint32_t mask = uint32_t { 1 } << bit_index;
return x ? (block & ~mask) : (block | mask);
}
使用 GodBolt,我为这两个选项中的每一个都获得了不同优化的代码,随着我们更改平台和编译器,这些代码也会有所不同。这是 Skylake 的 example(或者更好的是,请查看 this version,它是相同的代码,但拆分为更多的 C 语句,以便您可以更好地将程序集与 C 代码相关联)。
GCC 8.2 汇编:
bit_assign_1:
movzx eax, sil
btr edi, eax
movzx edx, dl
shlx eax, edx, eax
or eax, edi
ret
bit_assign_2:
mov ecx, 1
shlx esi, ecx, esi
andn eax, esi, edi
or esi, edi
test dl, dl
cmove eax, esi
ret
clang 7.0 程序集:
bit_assign_1: # @bit_assign_1
btr edi, esi
shlx eax, edx, esi
or eax, edi
ret
bit_assign_2: # @bit_assign_2
mov eax, edi
btr eax, esi
bts edi, esi
test edx, edx
cmovne edi, eax
mov eax, edi
ret
我还没有对此进行任何基准测试。