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);

The above is printing "1". What am I doing wrong?

  • What is the output if you do `printf("%ld", mask);` before the last line? – Chriszuma Jun 30 '11 at 19:32
  • I don't think this is the only problem, but you should use `1ULL` instead of `1LL`, since a `1 << 63` won't fit into a signed long long. Can you print `mask` so we can determine which function the bug is in? – ughoavgfhw Jun 30 '11 at 19:33
  • printf("%llu", mask); prints 10. But the bitsToInt64() must be working before i am using uint64_t as bitboards for chess pieces and they are all getting/setting correctly... –  Jun 30 '11 at 19:40

2 Answers2

2

Your shifting of 1LL, which is signed, yields undefined behavior. Shifting a 64bit signed integer by 63 bits is thus allowed to make the compiler do funny things (like making daemons fly out of your nose).

The solution is to use 1ULL << x instead in this case.

See also this excellent article from an Chris Lattner of LLVM that explains why things like this can result in strange behavior.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
1

With the code below I was able to get the following output

(0xFF00000000000010) 9

Make sure you use the correct size values. The literal constants need ULL so that they match uint64_t and the for loop variables only need to be an int, as well as the return value 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);
Joe
  • 56,979
  • 9
  • 128
  • 135
  • Just copied and pasted it again I am still getting what I posted. I am running x64 intel mac and gcc, uint64_t is typedef'd as unsigned long long. I am also able to get the same results with your original code. What compiler, OS, architecture are you on? – Joe Jun 30 '11 at 20:03
  • Just updated my last comment, wonder if it some compiler flag or optimization that is causing that for you. – Joe Jun 30 '11 at 20:07
  • (0x0000000000000010) 1 with the 0x%016llX but thats still not right. I am doing plan old `gcc input -o output` with no flags –  Jun 30 '11 at 20:08
  • Here is something fun to do, make them all 1's then if your output looks like 0x00000000FFFFFFFF, your long long is not quite as long as you think. – Joe Jun 30 '11 at 20:13
  • OMFG it was because i wasnt importing the a header file in one of the files that uses these functions. No warnings or anything, just a half working function... unbelievable. thanks for the help –  Jun 30 '11 at 20:31
  • Glad you figured out, were you just missing ``? I would like to update the answer so someone can find the solution easier. – Joe Jun 30 '11 at 20:39