1
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”。我究竟做错了什么?

4

2 回答 2

2

已签名的 转移会1LL产生未定义的行为。因此,允许将 64 位有符号整数移动 63 位,以使编译器做一些有趣的事情(比如让守护进程飞出你的鼻子)。

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

另请参阅LLVM 的 Chris Lattner 的这篇优秀文章,该文章解释了为什么这样的事情会导致奇怪的行为。

于 2011-06-30T19:48:03.297 回答
1

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

(0xFF00000000000010) 9

确保使用正确的尺寸值。文字常量需要ULL与 uint64_t 匹配,for 循环变量只需为 int,以及 for 的返回值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);
于 2011-06-30T19:45:49.923 回答