Thread: bit shifting...undefined behaviour?

  1. #1
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708

    bit shifting...undefined behaviour?

    given the following code:

    Code:
    unsigned
    mask = (~unsigned() << 1) >> 1;
    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?
    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;
    }

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    This shouldn't even compile. Did you mean:
    Code:
    unsigned
    mask = (~0u << 1) >> 1;
    Or
    Code:
    unsigned
    mask = (~unsigned() << 1) >> 1;
    Both output 2147483647.

    By the way, is the left-shift needed?
    Last edited by anon; 10-22-2007 at 10:42 AM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Code:
    ~unsigned
    This even compiles?
    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

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    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;
    }

  5. #5
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    Code:
    #include <bitset>
    #include <iostream>
    
    int main( void ) {
      std::bitset<sizeof(unsigned)*8> mask_set( (~unsigned()<<1)>>1 );
      std::cout<< mask_set;
    
      return 0;
    }
    My output: "01111111111111111111111111111111" ... seems right, no?

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    835
    Quote Originally Posted by Sebastiani View Post
    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)?
    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.

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    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;
    }

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Sebastiani View Post
    right, thanks. I'm wondering if the two shifts were just optimized out? I'll check it out.
    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.

  9. #9
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    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

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    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;
    }
    when called like this:

    Code:
    int
    main(void)
    {
           std::cout << (int)half_max<unsigned char>() << std::endl;
    }
    the output is: 255

    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;
    }
    the output is: 127

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

  11. #11
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    You try the debugger? There's a lot of that going around these days.

  12. #12
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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."

  13. #13
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    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;
    }

  14. #14
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    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;
    }
    is that a guaranteed solution?

    [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 11: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;
    }

  15. #15
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    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

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 11-23-2007, 01:48 PM
  2. Bit Shifting And Masking
    By Brad0407 in forum C Programming
    Replies: 3
    Last Post: 10-19-2005, 03:35 PM
  3. How to: Use OpenGL with Jgrasp
    By Pickels in forum Game Programming
    Replies: 3
    Last Post: 08-30-2005, 10:37 AM
  4. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM
  5. qt help
    By Unregistered in forum Linux Programming
    Replies: 1
    Last Post: 04-20-2002, 09:51 AM