长计数位不能按预期工作

时间:2011-06-30 19:25:14

标签: c bitwise-operators tdm-mingw

uint64_t bitsToInt64(char *bs) {
    uint64_t r, i;
    r = 0;
    for(i = 0; i < 64; i++)
        if(bs[i] == 1) 
            r |= 1LL << i;          
    return r;
}

int countBits64(uint64_t i) {
    uint64_t x, t;
    t = 0LL;
    for(x = 0LL; x < 64LL; x++) {
        if(i & (1LL << x))
            t += 1;
    }
    return t;
}

char bits [] = { 
    0, 0, 0, 0, 1, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1,};

uint64_t mask = bitsToInt64(bits);
int nbits = countBits64(mask);
printf("%d", nbits);

以上是打印“1”。我做错了什么?

2 个答案:

答案 0 :(得分:2)

您对已签名的1LL进行转换,会产生undefined behavior。因此,允许将64位带符号的整数移位63位使编译器做有趣的事情(如making daemons fly out of your nose)。

解决方案是在这种情况下使用1ULL << x

另请参阅LLVM的Chris Lattner的this excellent article,其中解释为什么这样的事情会导致奇怪的行为。

答案 1 :(得分:1)

使用下面的代码,我能够获得以下输出

  

(0xFF00000000000010)9

确保使用正确的尺寸值。文字常量需要ULL,以便它们匹配uint64_t,而for循环变量只需要是一个int,以及countBits64的返回值。

uint64_t bitsToInt64(char *bs) {
    uint64_t r;
    int i;
    r = 0;
    for(i = 0; i < 64; i++)
        if(bs[i] == 1) 
            r |= 1ULL << i;          
    return r;
}

int countBits64(uint64_t i) {
    int x, t = 0;
    for(x = 0; x < 64; x++) {
        if(i & (1ULL << x))
            t += 1;
    }
    return t;
}

char bits [] = { 
    0, 0, 0, 0, 1, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1,};

uint64_t mask = bitsToInt64(bits);
int nbits = countBits64(mask);
printf("(0x%016llX) %d",mask, nbits);