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;

Printable View

- 10-22-2007Sebastianibit shifting...undefined behaviour?
given the following code:

Code:`unsigned`

mask = (~unsigned() << 1) >> 1;

- 10-22-2007anon
This shouldn't even compile. Did you mean:

Code:`unsigned`

mask = (~0u << 1) >> 1;

Code:`unsigned`

mask = (~unsigned**()**<< 1) >> 1;

By the way, is the left-shift needed? - 10-22-2007CornedBeeCode:
`~unsigned`

- 10-22-2007Sebastiani
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. - 10-22-2007twomersCode:
`#include <bitset>`

#include <iostream>

int main( void ) {

std::bitset<sizeof(unsigned)*8> mask_set( (~unsigned()<<1)>>1 );

std::cout<< mask_set;

return 0;

}

- 10-22-2007robatino
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. - 10-22-2007Sebastiani
right, thanks. I'm wondering if the two shifts were just optimized out? I'll check it out.

- 10-22-2007matsp
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 - 10-22-2007CornedBee
My gcc 4.1 gives the right result.

- 11-06-2007Sebastiani
o.k., I'm back with a working example of this wierd behaviour. =)

Code:`template <typename Unsigned>`

inline

Unsigned

half_max(void)

{

static

Unsigned

value = ~Unsigned() >> 1;

return value;

}

Code:`int`

main(void)

{

std::cout << (int)half_max<unsigned char>() << std::endl;

}

however, when I employ a temporary during the initialization:

Code:`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? - 11-06-2007twomers
You try the debugger? There's a lot of that going around these days.

- 11-06-2007brewbuck
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." - 11-06-2007Sebastiani
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.

- 11-07-2007Sebastiani
o.k. so considering the following code:

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] - 11-07-2007CornedBee
It looks guaranteed, but have you tried:

Code:`template <typename Unsigned>`

inline Unsigned half_max()

{

return std::numeric_limit<Unsigned>::max() >> 1;

}