Shift Operation

Discussion in 'C Programming' started by Nishu, Oct 9, 2006.

  1. Nishu

    Nishu Guest

    Hi All,

    Could you please explain whether C standard supports logical right
    shift operation using some operator?

    I know somewhere I read about >>> operator. I thought, it is in C but i
    think i'm wrong about it. No where google helps me determining this
    lapse in my memory. MSVC 6 compiler gives me error.

    Thanks && Regards,
    Nishu
    Nishu, Oct 9, 2006
    #1
    1. Advertising

  2. Nishu said:

    > Hi All,
    >
    > Could you please explain whether C standard supports logical right
    > shift operation using some operator?


    C's right shift operator, >>, works like this:

    A >> B will yield a result that is equivalent to A shifted right through B
    bit positions. If A is negative, the result is implementation-defined.

    There is also a >>= operator, of course, so that you can do A >>= B instead
    of A = A >> B

    > I know somewhere I read about >>> operator. I thought, it is in C


    No, 'fraid not.


    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
    Richard Heathfield, Oct 9, 2006
    #2
    1. Advertising

  3. Nishu

    Nishu Guest

    Richard Heathfield wrote:
    > Nishu said:
    >
    > > Hi All,
    > >
    > > Could you please explain whether C standard supports logical right
    > > shift operation using some operator?

    >
    > C's right shift operator, >>, works like this:
    >
    > A >> B will yield a result that is equivalent to A shifted right through B
    > bit positions. If A is negative, the result is implementation-defined.


    If i take a signed integer, so right shifting a negative int should
    give me another negative int (signed arithmetic) or a positive integer.
    Is this C standard defines or implementation defines?

    Actually i want to know whether
    long A;
    A = 0xFFFFFFFF;

    A >>= 1;

    A &= 0x80000000

    if(A)
    {
    printf("operator is arithmetic right shift");
    }
    else
    {
    printf(" operator is logical right shift");
    }


    Thanks.
    Nishu
    Nishu, Oct 9, 2006
    #3
  4. Nishu

    Richard Bos Guest

    "Nishu" <> wrote:

    > Could you please explain whether C standard supports logical right
    > shift operation using some operator?


    No. Or rather, not reliably.

    Right shifting on unsigned integers is, of course, neither logical nor
    arithmetical (or both, if you wish); zeros get shifted in from the high
    end, but there is no sign bit to copy or not to copy.

    Right shifting on signed integers is different for positive and negative
    signed integers.
    If the signed integer has a positive or zero value, zero bits are
    shifted in from the high end just as for unsigned types; it makes no
    difference whether this is because it is a logical shift, or whether
    it's an arithmetical shift with a zero sign bit being copied. A zero bit
    is, after all, equal to any other zero bit.
    If, however, the signed integer has a negative value, the resulting
    value is implementation-defined. This means that your program is not
    allowed to crash on this operation[1], but the Standard doesn't require
    any particular result. All it requires is that your implementation
    defines what the result will be. This could be a logical shift, an
    arithmetical shift, or something entirely different (which might makes
    sense on, e.g., one's-complement machines).

    So in short, _your compiler_ might use a logical right shift if you use
    the normal C >> shifting operator, but that assumption is not portable:
    there's no guarantee that this will work on the next platform you try it
    on.

    > I know somewhere I read about >>> operator. I thought, it is in C but i
    > think i'm wrong about it.


    There is indeed no such thing.

    Richard

    [1] Unlike _left_-shifting a signed integer where the result would
    overflow; that is undefined, and may therefore crash.
    Richard Bos, Oct 9, 2006
    #4
  5. In article <>,
    Nishu <> wrote:

    >If i take a signed integer, so right shifting a negative int should
    >give me another negative int (signed arithmetic) or a positive integer.
    >Is this C standard defines or implementation defines?


    Implementation. Except that those aren't the only two choices
    available to the implementation...



    >Actually i want to know whether


    >long A;
    >A = 0xFFFFFFFF;


    >A >>= 1;


    >A &= 0x80000000


    >if(A)
    >{
    >printf("operator is arithmetic right shift");
    >}
    >else
    >{
    >printf(" operator is logical right shift");
    >}


    You are presuming that A = 0xFFFFFFFF will store a negative number
    in A. That is a bad assumption:

    1) long might have more than 32 bits, in which case 0xFFFFFFFF
    would just be a regular signed number. It is not uncommon for long
    to be 64 bits with int being 32 bits, short 16 bits, char 8 bits.
    But it is also not uncommon for int and long both to be the same size
    of 32 bits; there are also a number of compilers for which
    long is 32 bits, int is 16 bits...

    2) 0xFFFFFFFF is not specifically indicated as a long constant via an 'L'
    suffix; interpretation of it starts out by considering it as a
    signed int. No negative sign is present in the number, so the
    compiler will inspect to determine whether 0xFFFFFFFF fits within
    the positive range of signed int on that system; if it does then
    0xFFFFFFFF would be considered a positive signed int and there would
    then be an implicit cast of that positive signed int into a long for
    storage into A; as long is promised to be at least as wide as int,
    that would either involve leaving the number unchanged or else
    widening it if necessary; widening on most systems would involve
    sticking the value in the low bits and zero-filling the upper bits,
    but int and long need not have the same internal padding bit structures
    so an actual representation change might take place.

    If the compiler determines that 0xFFFFFFFF does not fit within
    the positive range of signed int, then it would reconsider it as
    potentialy being a positive signed long; if it does not fit within
    a positive signed long, then it would convert it to unsigned long, which
    it should fit into. So you would now have an unsigned long constant
    token and you would have a simple long destination to store it into.
    The C standard says that if you attempt to store an unsigned
    value into a signed location, and the unsigned value fits within
    the positive range of the signed type, then the positive value
    will be stored -- but it also says that if the unsigned value does
    *not* fit within the positive range of the signed type, that the
    result of the conversion is up to the implementation. Thus,
    long A = 0xFFFFFFFF is not necessarily going to produce a negative
    result in A, even if the implementation happens to use 32 bit long.
    --
    I was very young in those days, but I was also rather dim.
    -- Christopher Priest
    Walter Roberson, Oct 9, 2006
    #5
  6. Nishu said:

    > Richard Heathfield wrote:


    <snip>

    >> If A is negative, the result is implementation-defined.

    >
    > If i take a signed integer, so right shifting a negative int should
    > give me another negative int (signed arithmetic) or a positive integer.
    > Is this C standard defines or implementation defines?


    If A is negative, the result is implementation-defined.

    > Actually i want to know whether
    > long A;
    > A = 0xFFFFFFFF;
    >
    > A >>= 1;
    >
    > A &= 0x80000000
    >
    > if(A)
    > {
    > printf("operator is arithmetic right shift");
    > }
    > else
    > {
    > printf(" operator is logical right shift");
    > }


    If A is negative, the result is implementation-defined.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
    Richard Heathfield, Oct 9, 2006
    #6
  7. Nishu

    Nishu Guest

    Walter Roberson wrote:
    > In article <>,
    > Nishu <> wrote:
    >
    > >If i take a signed integer, so right shifting a negative int should
    > >give me another negative int (signed arithmetic) or a positive integer.
    > >Is this C standard defines or implementation defines?

    >
    > Implementation. Except that those aren't the only two choices
    > available to the implementation...


    < snip>

    > The C standard says that if you attempt to store an unsigned
    > value into a signed location, and the unsigned value fits within
    > the positive range of the signed type, then the positive value
    > will be stored -- but it also says that if the unsigned value does
    > *not* fit within the positive range of the signed type, that the
    > result of the conversion is up to the implementation. Thus,
    > long A = 0xFFFFFFFF is not necessarily going to produce a negative
    > result in A, even if the implementation happens to use 32 bit long.


    Thanks. I got it. C is indeed very flexible and benevolent to
    compilers. :)

    -Nishu
    Nishu, Oct 9, 2006
    #7
  8. Nishu

    Guest

    Nishu wrote:


    > I know somewhere I read about >>> operator. I thought, it is in C but i
    > think i'm wrong about it.


    >>> (unsigned right shift) exists in Java <http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.19>, but not in standard C.
    , Oct 9, 2006
    #8
  9. Nishu posted:

    > I know somewhere I read about >>> operator.



    Maybe you could write one yourself? If you know that "unsigned int" and
    "signed int" have no padding, then you could simply do:

    int i = -57;

    *(unsigned*)&i >>= 4;

    Or maybe something like:

    i < 0 ? (i = -i) >>= 4, i = -i : i >>= 4

    --

    Frederick Gotham
    Frederick Gotham, Oct 9, 2006
    #9
  10. Nishu

    Flash Gordon Guest

    Frederick Gotham wrote:
    > Nishu posted:
    >
    >> I know somewhere I read about >>> operator.


    Where >>> is meant to be a logical shift right.

    > Maybe you could write one yourself? If you know that "unsigned int" and
    > "signed int" have no padding, then you could simply do:
    >
    > int i = -57;
    >
    > *(unsigned*)&i >>= 4;


    Given your limitations I believe this would work.

    > Or maybe something like:
    >
    > i < 0 ? (i = -i) >>= 4, i = -i : i >>= 4


    This one will overflow with INT_MIN if INT_MIN == -INT_MAX - 1, i.e. on
    most 2s complement machines.
    --
    Flash Gordon
    Flash Gordon, Oct 9, 2006
    #10
  11. Frederick Gotham wrote:
    > Nishu posted:
    > > I know somewhere I read about >>> operator.

    >
    > Maybe you could write one yourself? If you know that "unsigned int" and
    > "signed int" have no padding, then you could simply do:
    >
    > int i = -57;
    >
    > *(unsigned*)&i >>= 4;


    This is legal in C99 [not sure about C90]. But you may not get the
    'desired' result for sm or 1c machines.

    --
    Peter
    Peter Nilsson, Oct 10, 2006
    #11
  12. Nishu

    Nishu Guest

    Frederick Gotham wrote:
    > Nishu posted:
    >
    > > I know somewhere I read about >>> operator.

    >
    >
    > Maybe you could write one yourself? If you know that "unsigned int" and
    > "signed int" have no padding, then you could simply do:
    >
    > int i = -57;
    >
    > *(unsigned*)&i >>= 4;


    Typecasting is certainly good option. Thanks.

    (unsigned) i >>= 1; /* (Results in logical shift) */

    What is the purpose of doing it like *(unsigned*)&i >>= 1; ?

    -Nishu
    Nishu, Oct 10, 2006
    #12
  13. Nishu

    Chris Dollin Guest

    Nishu wrote:

    > Frederick Gotham wrote:
    >> Nishu posted:
    >>
    >> > I know somewhere I read about >>> operator.

    >>
    >> Maybe you could write one yourself? If you know that "unsigned int" and
    >> "signed int" have no padding, then you could simply do:
    >>
    >> int i = -57;
    >>
    >> *(unsigned*)&i >>= 4;

    >
    > Typecasting is certainly good option. Thanks.
    >
    > (unsigned) i >>= 1; /* (Results in logical shift) */


    Results in a disgnostic message, I hope. Cast-expressions are not
    lvalues.

    > What is the purpose of doing it like *(unsigned*)&i >>= 1; ?


    To bypass (in a somewhat clunky way) the restriction than cast-expressions
    are not lvalues. I /think/ that you still get undefined behaviour, but
    it might only be implementation-defined. Or I might be wrong. We're
    having a warm October; maybe Hell is leaking.

    --
    Chris "Essen -9 and counting" Dollin
    "I'm still here and I'm holding the answers" - Karnataka, /Love and Affection/
    Chris Dollin, Oct 10, 2006
    #13
  14. In article <qDxWg.14659$>,
    Frederick Gotham <> wrote:

    > *(unsigned*)&i >>= 4;


    Why not use the more transparent

    i = ((unsigned)i) >> 4;

    Taking the address of a variable may well prevent the compiler from
    putting it in a register, though a sufficiently clever compiler would
    not be fooled.

    -- Richard
    Richard Tobin, Oct 10, 2006
    #14
  15. Nishu wrote:

    > If i take a signed integer, so right shifting a negative int should
    > give me another negative int (signed arithmetic)


    Why would you ever want to do an "arithmetic" right shift on a negative
    number?

    Even if the "sign" bit got shifted into the top bits, the result is
    mostly mathematically useless. i.e. shift of -1 on a two's complement
    machine gives you .....
    Ancient_Hacker, Oct 10, 2006
    #15
  16. In article <>,
    Ancient_Hacker <> wrote:

    >Why would you ever want to do an "arithmetic" right shift on a negative
    >number?


    To divide by 2?

    >Even if the "sign" bit got shifted into the top bits, the result is
    >mostly mathematically useless. i.e. shift of -1 on a two's complement
    >machine gives you .....


    -1, which is (-1)/2 rounded down (which is the behaviour I usually
    want from integer division).

    -- Richard
    Richard Tobin, Oct 10, 2006
    #16
  17. Nishu posted:

    > (unsigned) i >>= 1; /* (Results in logical shift) */



    As Chris mentioned, you might want to set your compiler to Strict C Mode if
    it compiles that for you. No case ever results in an L-value in C.

    --

    Frederick Gotham
    Frederick Gotham, Oct 10, 2006
    #17
  18. Richard Tobin posted:


    > i = ((unsigned)i) >> 4;



    If I'm not mistake, this will not retain the original bit-pattern on systems
    other than 2's complement.

    --

    Frederick Gotham
    Frederick Gotham, Oct 10, 2006
    #18
  19. Frederick Gotham posted:

    > No case ever results in an L-value in C.


    Typo correction:


    No CAST ever results in a...


    --

    Frederick Gotham
    Frederick Gotham, Oct 10, 2006
    #19
  20. Frederick Gotham wrote:
    > Richard Tobin posted:
    > > i = ((unsigned)i) >> 4;

    >
    > If I'm not mistake, this will not retain the original bit-pattern on systems
    > other than 2's complement.


    If you care about the bit pattern, you probably shouldn't be using
    signed integers anyway.
    =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=, Oct 10, 2006
    #20
    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. Roberto Gallo

    Shift - byte[] buf shift

    Roberto Gallo, Jan 27, 2004, in forum: Java
    Replies:
    3
    Views:
    2,049
    Thomas Schodt
    Jan 27, 2004
  2. Wenjie
    Replies:
    3
    Views:
    1,035
    Ron Samuel Klatchko
    Jul 11, 2003
  3. Santosh Nayak

    Left Shift / Right Shift Operators

    Santosh Nayak, Nov 30, 2006, in forum: C Programming
    Replies:
    16
    Views:
    1,450
    CBFalconer
    Nov 30, 2006
  4. Sanny
    Replies:
    38
    Views:
    3,397
    Thomas Richter
    Apr 29, 2011
  5. devphylosoff

    what "shift" does, if not "$_ = shift;" ?

    devphylosoff, Nov 29, 2007, in forum: Perl Misc
    Replies:
    3
    Views:
    326
    Michele Dondi
    Dec 4, 2007
Loading...

Share This Page