Search code examples
cmicro-optimizationbitarray

Unset the most significant bit in a word (int32) [C]


How can I unset the most significant setted bit of a word (e.g. 0x00556844 -> 0x00156844)? There is a __builtin_clz in gcc, but it just counts the zeroes, which is unneeded to me. Also, how should I replace __builtin_clz for msvc or intel c compiler?

Current my code is

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

UPDATE: Ok, if you says that this code is rather fast, I'll ask you, how should I add a portability to this code? This version is for GCC, but MSVC & ICC?


Solution

  • Just round down to the nearest power of 2 and then XOR that with the original value, e.g. using flp2() from 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
    }