开发者

Strange bit twiddling bug

开发者 https://www.devze.com 2023-02-19 19:42 出处:网络
I have a simple function: int bitcount( unsigned ); int shiftbit( unsigned val ) { return (int)(~0U << (( sizeof(int)*CHAR_BIT ) - bitcount(val)));

I have a simple function:

int bitcount( unsigned );

int shiftbit( unsigned val ) {
    return (int)(~0U << (( sizeof(int)*CHAR_BIT ) - bitcount(val)));
}

I'm counting the number of bits in an int and then creating a bitmask which has that number of bits left justified. For example, 0xABCD has 10 bits set and returns the mask 0xFFC0000.

The function works great except when the bitcount is zero in which case I get -1, 0xffffffff when I should just be getting an empty bitmask, i.e. 0x0. It's just not clear to me why it should work for every case except zero.

Answer

So I ended up changing the code as follows, which works fine and should be portable:

int shiftbit( unsigned val ) {
    int bCount = bitcount(val);
    return开发者_开发百科 bCount ? (~0 << (( sizeof(int)*CHAR_BIT ) - bCount)) : 0;
}


The result of a shift operation is undefined if the number of shifted bits is greater than or equal to the number of bits in the shifted value. So, shifting a 32-bit value by 32 isn't guaranteed to produce anything in particular.


Because in C the result is undefined if you shift an operand having a size of x bits by x bits. So for example 1 << 32 is undefined (assuming sizeof(int) == 4)


In C, the result of a shift is implementation-dependent. With x86 processors, you can actually be sure that the shift operand is modulo-32 (in 32-bit mode). See page 3-623 of this document:

ftp://download.intel.com/design/intarch/manuals/24319101.pdf

"The destination operand can be a register or a memory location. The count operand can be an immediate value or register CL. The count is masked to five bits, which limits the count range to 0 to 31. A special opcode encoding is provided for a count of 1"

0

精彩评论

暂无评论...
验证码 换一张
取 消