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”。我做错了什么?
答案 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);