given the following code:
one would expect the result to have all but the most significant bit set. but when I compile this with gcc, all bits are set. is this addressed by the standard?Code:unsigned mask = (~unsigned() << 1) >> 1;
This is a discussion on bit shifting...undefined behaviour? within the C++ Programming forums, part of the General Programming Boards category; given the following code: Code: unsigned mask = (~unsigned() << 1) >> 1; one would expect the result to have ...
given the following code:
one would expect the result to have all but the most significant bit set. but when I compile this with gcc, all bits are set. is this addressed by the standard?Code:unsigned mask = (~unsigned() << 1) >> 1;
Last edited by Sebastiani; 10-22-2007 at 12:19 PM. Reason: syntax error
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
This shouldn't even compile. Did you mean:
OrCode:unsigned mask = (~0u << 1) >> 1;
Both output 2147483647.Code:unsigned mask = (~unsigned() << 1) >> 1;
By the way, is the left-shift needed?
Last edited by anon; 10-22-2007 at 10:42 AM.
I might be wrong.
Quoted more than 1000 times (I hope).Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
This even compiles?Code:~unsigned
All the buzzt!
CornedBee
"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
sorry, that was a typo. anyway, to put it more clearly, shouldn't a shift always produce cleared bits in the vacated positions (unless the number of shifts exceeds the size of the data type, which is undefined)?
>> Both output 2147483647.
well, assuming a 4 byte integer, yes. but I get different results depending on the compiler.
>> By the way, is the left-shift needed?
no. I was just giving an example.
Last edited by Sebastiani; 10-22-2007 at 12:26 PM.
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
My output: "01111111111111111111111111111111" ... seems right, no?Code:#include <bitset> #include <iostream> int main( void ) { std::bitset<sizeof(unsigned)*8> mask_set( (~unsigned()<<1)>>1 ); std::cout<< mask_set; return 0; }
For a left shift, yes. For a right shift, it depends on whether the integral type is signed or unsigned. For an unsigned type, yes again. For a signed type, it does either an arithmetic shift or a logical shift, depending on the machine (logical shift is what you're thinking of).
http://en.wikipedia.org/wiki/Arithmetic_shift
http://en.wikipedia.org/wiki/Logical_shift
Edit: AFAIK, nothing undefined happens if the number of shifts exceeds the size of the data type, it does what you would expect.
Last edited by robatino; 10-22-2007 at 12:32 PM.
right, thanks. I'm wondering if the two shifts were just optimized out? I'll check it out.
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
Whilst it's possible that some compiler optimizes the shifts out, I wouldn't think that's really appropriate, as a right shift on an unsigned value should shift in zero's, and a right shift should always shift in zero's (signed or unsigned).
But check the code to make sure.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
My gcc 4.1 gives the right result.
All the buzzt!
CornedBee
"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
o.k., I'm back with a working example of this wierd behaviour. =)
when called like this:Code:template <typename Unsigned> inline Unsigned half_max(void) { static Unsigned value = ~Unsigned() >> 1; return value; }
the output is: 255Code:int main(void) { std::cout << (int)half_max<unsigned char>() << std::endl; }
however, when I employ a temporary during the initialization:
the output is: 127Code:template <typename Unsigned> inline Unsigned half_max(void) { static Unsigned value = Unsigned(~Unsigned()) >> 1; return value; }
any ideas as to what is causing this to happen?
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
You try the debugger? There's a lot of that going around these days.
When you use ~ to invert bits, the result is not the same type as what you put in -- the result is AN INT. Given this information, you can probably figure out what's happening with that temporary.
EDIT: In other words, the type of "~Unsigned()" is NOT "Unsigned."
you're right! and all along I thought it was a compiler bug, when in fact it was just another backward idiosyncrasy of the language. thank you very much, brewbuck.
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
o.k. so considering the following code:
is that a guaranteed solution?Code:template <typename Integer> Integer generate_inversion_mask_(void) { Integer zero = 0, one = 1, mask = zero; for(Integer bit = one; bit != zero; bit <<= one) { mask |= bit; } return mask; } template <typename Integer> inline Integer inverse(Integer value) { static Integer mask = generate_inversion_mask_<Integer>(); return value ^ mask; } template <typename Unsigned> inline Unsigned half_max(void) { static Unsigned value = inverse(Unsigned()) >> 1; return value; }
[edit]
come to think of it, I may be over-thinking this. the standard probably guarantees the result of a bitwise operations to fit into the largest integral type, which would mean the simplest solution would be to use a temporary - is that correct?
[/edit]
Last edited by Sebastiani; 11-07-2007 at 10:54 AM. Reason: annotation
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
It looks guaranteed, but have you tried:
?Code:template <typename Unsigned> inline Unsigned half_max() { return std::numeric_limit<Unsigned>::max() >> 1; }
All the buzzt!
CornedBee
"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law