shifting bits, shift 32 bits on 32 bit int

Discussion in 'C++' started by GGG, May 26, 2004.

  1. GGG

    GGG Guest

    Noticed something odd in the way bit shifting was working today.

    As far as I have ever heard, shifting will shift in zeros(signed ints
    aside)

    However I foudn something odd when I am shifting exactly the number of
    bits in a value... i.e.


    uint32_t x = 5;
    uint32_t y = x << 32;
    uint32_t z = x << 32;

    In the above example y and z are both still 5. Why is this?

    Now I understand doing a shift like this seems silly, but in this code
    sometimes the resulting shift validly turns out to be exactly the
    number of bits in that data type, and expects the result to be 0.

    I can change the code to handle this special case... I was just
    wondering why this was happening..
     
    GGG, May 26, 2004
    #1
    1. Advertising

  2. GGG wrote:
    > Noticed something odd in the way bit shifting was working today.
    >
    > As far as I have ever heard, shifting will shift in zeros(signed ints
    > aside)
    >
    > However I foudn something odd when I am shifting exactly the number of
    > bits in a value... i.e.
    >
    >
    > uint32_t x = 5;
    > uint32_t y = x << 32;
    > uint32_t z = x << 32;
    >
    > In the above example y and z are both still 5. Why is this?
    >
    > Now I understand doing a shift like this seems silly, but in this code
    > sometimes the resulting shift validly turns out to be exactly the
    > number of bits in that data type, and expects the result to be 0.
    >
    > I can change the code to handle this special case... I was just
    > wondering why this was happening..


    It shifts the number of bits determined from the right operand by
    taking the remainder from dividing by the number of total bits in
    the left operand. Take 32, divide by 32, take the remainder, you
    get 0. That's the number of bits shifted to the left. IOW, none.

    If you do

    uint32_t x = 5;
    uint32_t y = x << 33;

    you will have y == (uint32_t)10 (most likely, given common meaning
    of 'uint32_t').

    V
     
    Victor Bazarov, May 26, 2004
    #2
    1. Advertising

  3. GGG

    Walter Tross Guest

    Victor Bazarov 2004-05-26 :

    > GGG wrote:
    >> Noticed something odd in the way bit shifting was working today.
    >>
    >> As far as I have ever heard, shifting will shift in zeros(signed ints
    >> aside)
    >>
    >> However I foudn something odd when I am shifting exactly the number of
    >> bits in a value... i.e.
    >>
    >>
    >> uint32_t x = 5;
    >> uint32_t y = x << 32;
    >> uint32_t z = x << 32;
    >>
    >> In the above example y and z are both still 5. Why is this?
    >>
    >> Now I understand doing a shift like this seems silly, but in this code
    >> sometimes the resulting shift validly turns out to be exactly the
    >> number of bits in that data type, and expects the result to be 0.
    >>
    >> I can change the code to handle this special case... I was just
    >> wondering why this was happening..

    >
    > It shifts the number of bits determined from the right operand by
    > taking the remainder from dividing by the number of total bits in
    > the left operand. Take 32, divide by 32, take the remainder, you
    > get 0. That's the number of bits shifted to the left. IOW, none.
    >
    > If you do
    >
    > uint32_t x = 5;
    > uint32_t y = x << 33;
    >
    > you will have y == (uint32_t)10 (most likely, given common meaning
    > of 'uint32_t').


    Exactly, and the reason is simple: most hardware simply takes as many bits
    from the shift value as needed, ignoring the higher valued bits.
    In the case of uint32_t, 5 bits. In other words,
    uint32_t(x) << y == uint32_t(x) << (y & 31)

    Walter Tross
     
    Walter Tross, May 26, 2004
    #3
  4. GGG

    Heinz Ozwirk Guest

    "GGG" schrieb

    > uint32_t x = 5;
    > uint32_t y = x << 32;
    > uint32_t z = x << 32;
    >
    > In the above example y and z are both still 5. Why is this?
    >
    > Now I understand doing a shift like this seems silly, but in this code
    > sometimes the resulting shift validly turns out to be exactly the
    > number of bits in that data type, and expects the result to be 0.


    It doesn't matter what you are expecting. The behaviour of shifts defined only if the value of the right operand is less than the number of bits in the left operand. So shifting a 32-bit value by 32 or more is undefined or at least not specified in the standard and each compiler may do whatever it thinks to be best.

    Heinz
     
    Heinz Ozwirk, May 26, 2004
    #4
  5. GGG

    GGG Guest

    Ah... I figured out what was really going on here.

    I originally got no compiler warnings from my real program, as the
    value I was shifting by was a variable.

    I should have payed better attention to my little test program.

    uint32_t x = 1 << 32;
    //here, x is still 1. Shift any 32 bit int by 32 bits and it stays the
    exact same number

    That gives a compiler warning because I am shifting by the size of the
    data type. The problem here is that it is really just multiplying by
    2^32. So... it stays that same. So in reality, shifting doesn't really
    "shift in zeros", it does multipication, making it look like it shifts
    in zeros. This only becomes apparent when I am shifting by the actual
    data type size.


    So simply put, if you shift any integer by the number of bits in its
    data type, its going to be the exact same number.

    Shifting an 8 bit int by 8 bits is NOT 0, it is the same number.
    Shifting an 32 bit int by 32 bits is NOT 0, it is the same number.

    Kind of interesting I think...
     
    GGG, May 27, 2004
    #5
  6. GGG

    Jeff Schwab Guest

    GGG wrote:
    > Ah... I figured out what was really going on here.
    >
    > I originally got no compiler warnings from my real program, as the
    > value I was shifting by was a variable.
    >
    > I should have payed better attention to my little test program.
    >
    > uint32_t x = 1 << 32;
    > //here, x is still 1. Shift any 32 bit int by 32 bits and it stays the
    > exact same number
    >
    > That gives a compiler warning because I am shifting by the size of the
    > data type. The problem here is that it is really just multiplying by
    > 2^32. So... it stays that same. So in reality, shifting doesn't really
    > "shift in zeros", it does multipication, making it look like it shifts
    > in zeros. This only becomes apparent when I am shifting by the actual
    > data type size.
    >
    >
    > So simply put, if you shift any integer by the number of bits in its
    > data type, its going to be the exact same number.
    >
    > Shifting an 8 bit int by 8 bits is NOT 0, it is the same number.
    > Shifting an 32 bit int by 32 bits is NOT 0, it is the same number.
    >
    > Kind of interesting I think...


    You're wrong. Read Heinz's post.
     
    Jeff Schwab, May 27, 2004
    #6
  7. GGG

    Jeff Schwab Guest

    Jeff Schwab wrote:
    > GGG wrote:
    >
    >> Ah... I figured out what was really going on here.
    >>
    >> I originally got no compiler warnings from my real program, as the
    >> value I was shifting by was a variable.
    >>
    >> I should have payed better attention to my little test program.
    >>
    >> uint32_t x = 1 << 32;
    >> //here, x is still 1. Shift any 32 bit int by 32 bits and it stays the
    >> exact same number
    >>
    >> That gives a compiler warning because I am shifting by the size of the
    >> data type. The problem here is that it is really just multiplying by
    >> 2^32. So... it stays that same. So in reality, shifting doesn't really
    >> "shift in zeros", it does multipication, making it look like it shifts
    >> in zeros. This only becomes apparent when I am shifting by the actual
    >> data type size.
    >>
    >>
    >> So simply put, if you shift any integer by the number of bits in its
    >> data type, its going to be the exact same number.
    >>
    >> Shifting an 8 bit int by 8 bits is NOT 0, it is the same number.
    >> Shifting an 32 bit int by 32 bits is NOT 0, it is the same number.
    >>
    >> Kind of interesting I think...

    >
    >
    > You're wrong. Read Heinz's post.


    Better yet, read the first part of section 5.8 of the ISO/IEC 14882:2003
    standard:

    The behavior is undefined if the right operand is negative,
    or greater than or equal to the length in bits of the
    promoted left operand.
     
    Jeff Schwab, May 27, 2004
    #7
  8. GGG

    Jack Klein Guest

    On Wed, 26 May 2004 22:42:52 +0200, "Heinz Ozwirk" <>
    wrote in comp.lang.c++:

    > "GGG" schrieb
    >
    > > uint32_t x = 5;
    > > uint32_t y = x << 32;
    > > uint32_t z = x << 32;
    > >
    > > In the above example y and z are both still 5. Why is this?
    > >
    > > Now I understand doing a shift like this seems silly, but in this code
    > > sometimes the resulting shift validly turns out to be exactly the
    > > number of bits in that data type, and expects the result to be 0.

    >
    > It doesn't matter what you are expecting. The behaviour of shifts defined
    > only if the value of the right operand is less than the number of bits in
    > the left operand. So shifting a 32-bit value by 32 or more is undefined or
    > at least not specified in the standard and each compiler may do whatever
    > it thinks to be best.
    >
    > Heinz


    First, please find the setting in your news posting software where you
    tell it to insert line breaks at some interval in the range of 65 to
    89 characters. Thank you.

    Next, you are partially correct. The value of the right operand must
    not only be less than the width in bits of the (promoted) left
    operand, it must also be greater than or equal to 0.

    Both a negative right operand, or one as large or larger than the
    number of bits in the promoted left operand cause undefined behavior.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, May 27, 2004
    #8
  9. (GGG) wrote in message news:<>...
    > Ah... I figured out what was really going on here.
    >
    > I originally got no compiler warnings from my real program, as the
    > value I was shifting by was a variable.
    >
    > I should have payed better attention to my little test program.
    >
    > uint32_t x = 1 << 32;
    > //here, x is still 1. Shift any 32 bit int by 32 bits and it stays the
    > exact same number
    >
    > That gives a compiler warning because I am shifting by the size of the
    > data type. The problem here is that it is really just multiplying by
    > 2^32. So... it stays that same.


    No, it doesn't. Unsigned arithmetic, including multiplying, works modulo
    2^n. Multiplying by 2^32 modulo 2^32 always gives you 0.

    What happens has been pointed out before: undefined behavior.

    Regards,
    Michiel Salters
     
    Michiel Salters, May 27, 2004
    #9
  10. GGG

    GGG Guest

    Jack Klein <> wrote in message news:<>...
    > On Wed, 26 May 2004 22:42:52 +0200, "Heinz Ozwirk" <>
    > wrote in comp.lang.c++:
    >
    > > "GGG" schrieb
    > >
    > > > uint32_t x = 5;
    > > > uint32_t y = x << 32;
    > > > uint32_t z = x << 32;
    > > >
    > > > In the above example y and z are both still 5. Why is this?
    > > >
    > > > Now I understand doing a shift like this seems silly, but in this code
    > > > sometimes the resulting shift validly turns out to be exactly the
    > > > number of bits in that data type, and expects the result to be 0.

    > >
    > > It doesn't matter what you are expecting. The behaviour of shifts defined
    > > only if the value of the right operand is less than the number of bits in
    > > the left operand. So shifting a 32-bit value by 32 or more is undefined or
    > > at least not specified in the standard and each compiler may do whatever
    > > it thinks to be best.
    > >
    > > Heinz

    >
    > First, please find the setting in your news posting software where you
    > tell it to insert line breaks at some interval in the range of 65 to
    > 89 characters. Thank you.
    >
    > Next, you are partially correct. The value of the right operand must
    > not only be less than the width in bits of the (promoted) left
    > operand, it must also be greater than or equal to 0.
    >
    > Both a negative right operand, or one as large or larger than the
    > number of bits in the promoted left operand cause undefined behavior.



    Ah, thanks for all the info. Sorry for the long lines... that always annoyed
    me too, I am now just stuck no real newsgroup access anymore and it really
    blows. I need to use Google to do it...(not to mentioned the ~8 hour delay
    when you post on google... I just have to remeber to add in a CR manually
    when I post....

    Anyways, thanks for setting me straight, my first clue should have been
    the compiler warnings that I wasn't paying attention too. Need to pay
    better attention...


    -grant
     
    GGG, May 27, 2004
    #10
  11. GGG

    Donar

    Joined:
    Jul 6, 2006
    Messages:
    1


    I just stumbled over the same problem, in another language though, and was pointed to this thread. Yes, I am aware, that the thread is a quite old one, but it may help as a future reference for others having the same problem ;)

    I looked up the Intel spec [1]. The result is /not/ undefined. The Intel spec reads literally:

    "The count is masked to 5 bits (or 6 bits if in 64-bit mode and REX.W is used). The count range is limited to 0 to 31 (or 63 if 64-bit mode and REX.W is used)."

    Kind regards
    //Herbert Glarner



    [1] "IA-32 IntelĀ® Architecture Software Developer's Manual, Volume 2B: Instruction Set Reference, N-Z", page 243
     
    Last edited: Jul 6, 2006
    Donar, Jul 6, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Wenjie
    Replies:
    3
    Views:
    1,074
    Ron Samuel Klatchko
    Jul 11, 2003
  2. Christian Vallant

    8 bit into 256 bit shift register

    Christian Vallant, May 23, 2006, in forum: VHDL
    Replies:
    8
    Views:
    4,032
    Mike Treseler
    May 24, 2006
  3. Schnoffos
    Replies:
    2
    Views:
    1,247
    Martien Verbruggen
    Jun 27, 2003
  4. Hal Styli
    Replies:
    14
    Views:
    1,697
    Old Wolf
    Jan 20, 2004
  5. Fore
    Replies:
    29
    Views:
    15,515
    Rashad
    Sep 21, 2008
Loading...

Share This Page