long long/uint64_t acting... weird (c++)

Programming, for all ages and all languages.
Post Reply
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

long long/uint64_t acting... weird (c++)

Post by Zacariaz »

basicly i can assign any value (allthough with warnings) i choose directly to the 64 bit integer but when using bitwise operators its acting strange:

Code: Select all

std::cout << sizeof(unsigned long long); /* outputs 8, which is correct */
unsigned long long test = 0;
test |= 1 << 30; /* test now contains the value 1,073,741,824 which is correct */
test |= 1 << 31; /* test now contains the value 18,446,744,071,562,067,968 when it should contain 3,221,225,472 */
test = 3221225472; /* test now contains the value 3,221,225,472 as it should, however the compiler gives a warning: "[Warning] this decimal constant is unsigned only in ISO C90" */
I dont supose there is anything that can be done as long as im running a 32 bit OS?
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Post by Colonel Kernel »

Try putting "ULL" after your integer constants.

Think about what's happening with test |= 1 << 31; step-by-step. First, the right hand side (1 << 31) is evaluated. At this point, the compiler only sees literal integers and the << operator -- it has no clue as to the type of the expression other than the literals, which have no special suffixes... Therefore it will default the type to "int". Before evaluating |=, the type of the right-hand expression must be converted from "int" to "unsigned long long", which results in automatic sign-extension. That's why you're getting such a huge number -- because the number you're ending up with is probably 0xFFFFFFFF80000000.

The compiler is only doing what you told it to do. Be careful!
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

Code: Select all

#include <iostream>
int main() {
  unsigned long long test = 0;
  for(char i = 0; i < 64; i++) {
    test |= 1ULL << i;
    std::cout << test << std::endl;
  }
  for(char i = 63; i > 0; i--) {
    test -= 1ULL << i;
    std::cout << test << std::endl;
  }
}
This little example works, im happy to say, but did i catch it all? Its kinda important i dont miss anything, as i will be using ull's alot and allso doing bitwise manipulation to them alot (butboard stuff)

Anyway, thanks!
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

Yes, you did catch it all.

It's easy: In olden C, if you didn't declare a variable, it was int by default. Otherwise, your definition specifies the width of the variable.

Same with numeric constants. Unless defined to a certain width, they are int, otherwise your definition... you get the idea.

So that leaves the 0, the 64 and the 63 as constants. The first casts to ULL just fine, the other two are loop counters that have nothing to do with 64bit.

Erm... I think that should be a 64 in the second loop too, though.
Every good solution is obvious once you've found it.
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

Solar wrote:The first casts to ULL just fine, the other two are loop counters that have nothing to do with 64bit.
Im not quite sure what you mean. Did i cast ull anywhere not needed?
Solar wrote:Erm... I think that should be a 64 in the second loop too, though.
Yes, if i wanted the last printout to be 0, but then in order to achive perfection i would have to make the first out be 0 as well, but that would lieve an imperfect looking code with cout's outside the loops! cant have that ;)
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

One last question...

Code: Select all

#include <iostream>
#include <bitset>
int main() {
  std::bitset<64> test;
  test = 0xffffffffffffffffull;
  std::cout << test;
}
output = 0000000000000000000000000000000011111111111111111111111111111111

Yes it is a looong stream of bits, however the problem is obious. Only 32 bits of the 64 is assigned to the bitset.
Is there anything that can be done about that?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

I would think about overloading the assignment operator for (unsigned) long longs
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

Is that actually operator=() called there, or the bitset( unsigned long ) constructor? Anyway, the point is valid: As C++ doesn't know about unsigned long long, it isn't taken into account "automagically".
Every good solution is obvious once you've found it.
Post Reply