当左移不等于2乘以时

时间:2015-12-16 10:31:27

标签: c bit-manipulation kernighan-and-ritchie

我尝试了KR练习2.1 - 通过直接计算确定long变量的范围。

#include <stdio.h>
#include <limits.h>

int main()
{
    unsigned short long_bits =  sizeof( long ) * CHAR_BIT;
    printf( "LONG_MAX   = %ld\n", ( 1L << ( long_bits - 1 ) ) - 1 );
    printf( "LONG_MIN   = %ld\n", ( -1 ) * ( 1L << ( long_bits - 1 ) ) );
    printf( "ULONG_MAX (1) = %lu\n", ( 1UL << long_bits ) - 1 );    // doesn't work

    printf( "ULONG_MAX (2) = %lu\n", 2*( 1UL << ( long_bits - 1 ) ) - 1 );  // work
    printf( "\n" );
}
  • ULONG_MAX (1) = 0错了,因为我认为左移溢出了。
  • ULONG_MAX (2) = 18446744073709551615似乎是正确的,将最后一个左移替换为2。

所以看起来左移运算符会出现溢出,但乘法不会?此中间计算2*( 1UL << ( long_bits - 1 ) ) 是否将提升为long以外的某种类型?在我的机器中,longlong long完全相同(8字节)。

编辑: 正如Lundin指出的那样,ULONG_MAX所需要的只是printf( "ULONG_MAX = %lu\n", ~0L );

在这种情况下使用左移导致UB,并且乘以2也可能是UB(尽管情况2的结果看起来正确)。

1 个答案:

答案 0 :(得分:4)

左移位值的行为仅在您左移的数量小于类型的大小时定义。因此,1UL << long_bits是未定义的行为,任何事情都可能发生,包括从鼻子里飞出来的dæmons。

n为我们正在使用的类型中的位数。在实践中,根据平台,在这种情况下会发生两种行为:任何左移n或更多产生0(因为整个位模式被移出),或者左移以模n为模,因此左移n个位置就像左移0个位置一样,产生1UL << 01