Отсоедините самый старший бит в слове (int32)

Как я могу отключить наиболее значительный бит бит (например, 0x00556844 -> 0x00156844)? В gcc есть __builtin_clz , но он просто подсчитывает нули, которые мне не нужны. Кроме того, как мне заменить __builtin_clz для компилятора msvc или intel c?

Текущий код

  int msb = 1<< ((sizeof(int)*8)-__builtin_clz(input)-1); int result = input & ~msb; 

UPDATE: Хорошо, если вы скажете, что этот код довольно быстрый, я спрошу вас, как мне добавить переносимость этого кода? Эта версия предназначена для GCC, но MSVC и ICC?

Просто округлите до ближайшей мощности 2, а затем XOR, которая с исходным значением, например, используя flp2() от Hacker’s Delight :

 uint32_t flp2(uint32_t x) // round x down to nearest power of 2 { x = x | (x >> 1); x = x | (x >> 2); x = x | (x >> 4); x = x | (x >> 8); x = x | (x >>16); return x - (x >> 1); } uint32_t clr_msb(uint32_t x) // clear most significant set bit in x { msb = flp2(x); // get MS set bit in x return x ^ msb; // XOR MS set bit to clear it } 

Если вы действительно заинтересованы в производительности, лучший способ очистить msb недавно изменился для x86 с добавлением инструкций BMI.

В сборке x86:

 clear_msb: bsrq %rdi, %rax bzhiq %rax, %rdi, %rax retq 

Теперь перепишитесь на C и дайте компилятору исправить эти инструкции, грациозно унизив их для архитектур без архитектуры x86 или старых процессоров x86, которые не поддерживают инструкции BMI.

По сравнению с ассемблерным кодом версия C действительно уродливая и многословная. Но, по крайней мере, он соответствует цели переносимости. И если у вас есть необходимые аппаратные средства и директивы компилятора (-mbmi, -mbmi2) для соответствия, вы вернетесь к красивому ассемблеру после компиляции.

Как написано, bsr () полагается на встроенный GCC / Clang. Если вы планируете использовать другие компиляторы, вы можете заменить эквивалентный переносимый C-код и / или разные встроенные компиляторы.

 #include  #include  uint64_t bsr(const uint64_t n) { return 63 - (uint64_t)__builtin_clzll(n); } uint64_t bzhi(const uint64_t n, const uint64_t index) { const uint64_t leading = (uint64_t)1 << index; const uint64_t keep_bits = leading - 1; return n & keep_bits; } uint64_t clear_msb(const uint64_t n) { return bzhi(n, bsr(n)); } int main(void) { uint64_t i; for (i = 0; i < (uint64_t)1 << 16; ++i) { printf("%" PRIu64 "\n", clear_msb(i)); } return 0; } 

Как монтажные, так и С-версии, естественно, заменяются 32-разрядными инструкциями, поскольку исходный вопрос задавался.

Ты можешь сделать

 unsigned resetLeadingBit(x) { return x & ~(0x80000000U >> __builtin_clz(x)) } 

Для MSVC существует _BitScanReverse , который составляет 31 -__ builtin_clz ().

Фактически, наоборот, BSR является естественной инструкцией x86, а gcc-int реализована как 31-BSR.