Thread: Confusing bit shift behaviour, bits set after right shift

  1. #1
    Registered User
    Join Date
    May 2013
    Posts
    3

    Confusing bit shift behaviour, bits set after right shift

    Hello,

    when I execute the following line of code...

    Code:
        
    printf("%x, %x, %x\n", (1 << 31), ((0x80000000) >> 31), ((1 << 31) >> 31));
    The result is: 80000000, 1, ffffffff. I understand the first two values, but why doesn't the last value = 1. Specifically, when I execute the following..

    Code:
    ((1 << 31) >> 31)
    ..why are all the bits positioned to the left of the right-bitshift operation set?

    Thanks.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Change the %x format specified to %d. You will probably find that some of the values are negative. Bitwise right shift of a signed integer with a negative value has an implementation defined result, e.g., maybe the bits were right shifted with 1 bits used to fill in the "shifted positions", thereby retaining the sign.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2013
    Posts
    3
    Quote Originally Posted by laserlight View Post
    Change the %x format specified to %d. You will probably find that some of the values are negative. Bitwise right shift of a signed integer with a negative value has an implementation defined result, e.g., maybe the bits were right shifted with 1 bits used to fill in the "shifted positions", thereby retaining the sign.
    Thanks Laserlight. You're right. When I change the printf to the following...

    Code:
     printf("%x, %x, %x\n", (1 << 31), ((0x80000000) >> 31), (((uintptr_t)1 << 31) >> 31));
    ..it "works". The result is: 80000000, 1, 1.

    Cheers

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The cast to uintptr_t seems semantically wrong. I would expect: ((1u << 31) >> 31));
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    May 2013
    Posts
    3
    I see, much better.

    Thanks again.

  6. #6
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by laserlight View Post
    Bitwise right shift of a signed integer with a negative value has an implementation defined result, e.g., maybe the bits were right shifted with 1 bits used to fill in the "shifted positions", thereby retaining the sign.
    I thought this was a defined behavior in C (right shifting of signed negative numbers retains the sign). From VS2005

    Bitwise Shift Operators (C)

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by rcgldr
    I thought this was a defined behavior in C (right shifting of signed negative numbers retains the sign).
    Well, it is defined, implementation defined:
    Quote Originally Posted by C99 Clause 6.5.7 Paragraph 5
    The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2**E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.
    I have taken the liberty of using ** to denote exponentiation.

    Quote Originally Posted by rcgldr
    Hence that implementation has defined how it would deal with such a case.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by rcgldr View Post
    I thought this was a defined behavior in C (right shifting of signed negative numbers retains the sign).
    Quote Originally Posted by laserlight View Post
    Well, it is defined, implementation defined:
    Was it ever a defined operation in ANSI C or older versions (C89, C90, K&R C)? I have seen it implemented in this same way in some old 1980's compilers for Motorola 68000, Intel X86 and 1990's compilers for the ARM, from several different vendors for each processor type. Seems unusual that they all decided to implement right shift as an arithmetic shift.

    One issue I can see is that a ones complement machine would be different than a two's complement machine, but one's complement machines are rare, and I don't know if C99 specifies how signed numbers are to be implemented.

    Thanks for the info. I wasn't aware of this, and the microsoft references don't state which operations are implementation dependent.
    Last edited by rcgldr; 05-18-2013 at 03:37 PM.

  9. #9
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Are constant values like 0x80000000 always considered to be unsigned (for a 32 bit value)?

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by rcgldr
    Was it ever a defined operation in ANSI C or older versions (C89, C90, K&R C)?
    The rule is the same for C89/C90. I have no clue for K&R.

    Quote Originally Posted by rcgldr
    I don't know if C99 specifies how signed numbers are to be implemented.
    As far as I remember, there are three options: sign and magnitude, one's complement, and two's complement.

    Quote Originally Posted by megafiddle
    Are constant values like 0x80000000 always considered to be unsigned (for a 32 bit value)?
    It depends. Since it is in hexadecimal representation, it could be unsigned if it cannot fit into the range of a corresponding signed integer type.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by rcgldr View Post
    Was it ever a defined operation in ANSI C or older versions (C89, C90, K&R C)?
    In K&R, 2nd edition from 1988, it's implementation-defined. There is an appendix which lists all changes to the first edition and the behaviour of right shifts isn't mentioned.

    In a tutorial from 1974, Kernighan mentions machines for both arithmetic and logical shifts.

    Hence, I guess it was never defined.

    Bye, Andreas

  12. #12
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by AndiPersti View Post
    In a tutorial from 1974, Kernighan mentions machines for both arithmetic and logical shifts.
    On a side note, the "H6070" mentioned in the tutorial refers to the Honeywell 6070 (which was the GE 655). Wiki article:

    GE-600 series - Wikipedia, the free encyclopedia

    PDP-11:

    PDP-11 - Wikipedia, the free encyclopedia

    IBM 360:

    IBM System/360 - Wikipedia, the free encyclopedia

    That tutorial is the first time I've seen C / C++ right shift optionally defined as a logical shift for signed numbers. In all the other instances I'm aware of a right shift on a signed number is arithmetic and copies the sign, at least on two's complement machines.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. logical shift and arithmetic shift.(bit shifting in C )
    By A34Chris in forum C Programming
    Replies: 20
    Last Post: 09-03-2012, 11:22 AM
  2. How to shift the bits of an array?
    By manasij7479 in forum C Programming
    Replies: 6
    Last Post: 08-13-2011, 07:42 PM
  3. Shift all '1' bits in a number to the left end
    By beatbox32 in forum C Programming
    Replies: 10
    Last Post: 07-06-2011, 01:38 PM
  4. C how to Shift bits in BCD
    By evariste in forum C Programming
    Replies: 13
    Last Post: 12-17-2010, 03:50 AM
  5. Shift Key
    By gnu-ehacks in forum A Brief History of Cprogramming.com
    Replies: 14
    Last Post: 01-31-2002, 05:47 PM