Shifting unsigned long long values by 64 bits

Discussion in 'C Programming' started by krunalb, Jan 22, 2007.

  1. krunalb

    krunalb Guest

    Hi,

    I am trying to shift unsigned long long value by 64 bits and this is
    what i get

    #include <stdio.h>

    int main()
    {
    unsigned short shiftby= 64;
    fprintf(stderr, "Value (using hardcoded 64) : %llx\n", \
    (((unsigned long long) ~0ULL) << 64));
    fprintf(stderr, "Value (w/o hardcoded 64) : %llx\n", \
    (((unsigned long long) ~0ULL) << shiftby));
    }

    gcc file.c
    t2.c: In function `main':
    t2.c:7: warning: left shift count >= width of type


    <IMPORTANT>
    Value (using hardcoded 64) : 0
    Value (w/o hardcoded 64) : ffffffffffffffff
    </IMPORTANT>

    Why is the behavior different if we try to shift value by 64 bits using
    a variable
    as against direct numeric "64"?

    Regards,
    Krunal
     
    krunalb, Jan 22, 2007
    #1
    1. Advertising

  2. krunalb

    Barry Guest

    "krunalb" <> wrote in message
    news:...
    > Hi,
    >
    > I am trying to shift unsigned long long value by 64 bits and this is
    > what i get
    >
    > #include <stdio.h>
    >
    > int main()
    > {
    > unsigned short shiftby= 64;
    > fprintf(stderr, "Value (using hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << 64));
    > fprintf(stderr, "Value (w/o hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << shiftby));
    > }
    >
    > gcc file.c
    > t2.c: In function `main':
    > t2.c:7: warning: left shift count >= width of type
    >
    >
    > <IMPORTANT>
    > Value (using hardcoded 64) : 0
    > Value (w/o hardcoded 64) : ffffffffffffffff
    > </IMPORTANT>
    >
    > Why is the behavior different if we try to shift value by 64 bits using
    > a variable
    > as against direct numeric "64"?
    >
    > Regards,
    > Krunal
    >

    Its undefined behaviour.
     
    Barry, Jan 22, 2007
    #2
    1. Advertising

  3. krunalb wrote:
    > Hi,
    >
    > I am trying to shift unsigned long long value by 64 bits and this is
    > what i get
    >
    > #include <stdio.h>
    >
    > int main()
    > {
    > unsigned short shiftby= 64;
    > fprintf(stderr, "Value (using hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << 64));
    > fprintf(stderr, "Value (w/o hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << shiftby));
    > }
    >
    > gcc file.c
    > t2.c: In function `main':
    > t2.c:7: warning: left shift count >= width of type
    >
    >
    > <IMPORTANT>
    > Value (using hardcoded 64) : 0
    > Value (w/o hardcoded 64) : ffffffffffffffff
    > </IMPORTANT>
    >
    > Why is the behavior different if we try to shift value by 64 bits using
    > a variable
    > as against direct numeric "64"?
    >


    Quoth ISO/IEC 9899:1999:

    6.5.7 Bitwise Shift Operators
    [...]
    3 [...] If the value of the right operand is negative or is
    greater than or equal to the width of the promoted
    left operand, the behavior is undefined.


    Mark F. Haigh
     
    Mark F. Haigh, Jan 22, 2007
    #3
  4. krunalb

    Guest

    krunalb wrote:
    > Hi,
    >
    > I am trying to shift unsigned long long value by 64 bits and this is
    > what i get
    >
    > #include <stdio.h>
    >
    > int main()
    > {
    > unsigned short shiftby= 64;
    > fprintf(stderr, "Value (using hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << 64));
    > fprintf(stderr, "Value (w/o hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << shiftby));
    > }
    >
    > gcc file.c
    > t2.c: In function `main':
    > t2.c:7: warning: left shift count >= width of type
    >
    >
    > <IMPORTANT>
    > Value (using hardcoded 64) : 0
    > Value (w/o hardcoded 64) : ffffffffffffffff
    > </IMPORTANT>
    >
    > Why is the behavior different if we try to shift value by 64 bits using
    > a variable as against direct numeric "64"?


    It isn't on my AIX system, using the xlc compiler...

    It's undefined behaviour, the compiler is free to do what it likes and
    the compiler doesn't have to be consistent...
     
    , Jan 22, 2007
    #4
  5. krunalb wrote:
    >
    > Hi,
    >
    > I am trying to shift unsigned long long value by 64 bits and this is
    > what i get
    >
    > #include <stdio.h>
    >
    > int main()
    > {
    > unsigned short shiftby= 64;
    > fprintf(stderr, "Value (using hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << 64));
    > fprintf(stderr, "Value (w/o hardcoded 64) : %llx\n", \
    > (((unsigned long long) ~0ULL) << shiftby));
    > }
    >
    > gcc file.c
    > t2.c: In function `main':
    > t2.c:7: warning: left shift count >= width of type
    >
    > <IMPORTANT>
    > Value (using hardcoded 64) : 0
    > Value (w/o hardcoded 64) : ffffffffffffffff
    > </IMPORTANT>
    >
    > Why is the behavior different if we try to shift value by 64 bits using
    > a variable as against direct numeric "64"?


    As mentioned elsewhere, this is UB. However, this may explain the
    symptoms of UB that you are seeing on your particular platform. This
    is, of course, pure conjecture based on the observed results.

    1 - The compiler sees the hard-coded 64 bit shift and, knowing that
    the value is only 64 bits to begin with, knows the result would
    be zero, and compiles with a constant zero as the parameter.
    (Or, perhaps, actually did the caluclation, as both values are
    constants. In which case, it came up with the "expected" value
    of zero.)

    Note, too, the compiler warning for this line.

    2 - When shifting by "shiftby" instead, it needs to compile code to
    shift at the machine-code level, and places "64" in a register,
    and executes an "unsigned left shift" of that amount. The CPU,
    knowing that the operation is working on 64-bit values, only
    uses the lower 6 bits of the shift amount. In this case, that
    value is zero.

    I ran into (2) recently on code which worked just fine on a platform
    which supported 64-bit ints, but failed on a system which only supported
    32-bit ints. In my case, I was splitting a value into two 32-bit values
    to pass as parameters to a function. I did this by right-shifting the
    value by 32 bits to get the high-order 32 bits. On the 64-bit-aware
    platform, this worked just fine. On the 32-bit-only platform, the
    shift of 32 bits was, at the CPU level, treated as a zero-bit shift
    (the low-order 5 bits of the shift value being zero), causing the wrong
    value for the "high 32 bits" parameter to be passed. (It should, of
    course, been zero, as there were only the low-order 32 bits in the
    value to begin with. Instead, it duplicated the low-order bits as
    the high-order bits.)

    --
    +-------------------------+--------------------+-----------------------+
    | Kenneth J. Brody | www.hvcomputer.com | #include |
    | kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
    +-------------------------+--------------------+-----------------------+
    Don't e-mail me at: <mailto:>
     
    Kenneth Brody, Jan 22, 2007
    #5
  6. krunalb

    CBFalconer Guest

    krunalb wrote:
    >
    > I am trying to shift unsigned long long value by 64 bits and this
    > is what i get


    Try thinking a moment. If you shift off 64 bits of a 64 bit
    quantity, what do you have left?

    --
    <http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>

    "A man who is right every time is not likely to do very much."
    -- Francis Crick, co-discover of DNA
    "There is nothing more amazing than stupidity in action."
    -- Thomas Matthews
     
    CBFalconer, Jan 22, 2007
    #6
  7. "Kenneth Brody" <> wrote in message
    news:...
    >
    > As mentioned elsewhere, this is UB. However, this may explain the
    > symptoms of UB that you are seeing on your particular platform. This
    > is, of course, pure conjecture based on the observed results.
    >
    > 1 - The compiler sees the hard-coded 64 bit shift and, knowing that
    > the value is only 64 bits to begin with, knows the result would
    > be zero, and compiles with a constant zero as the parameter.
    > (Or, perhaps, actually did the caluclation, as both values are
    > constants. In which case, it came up with the "expected" value
    > of zero.)
    >
    > Note, too, the compiler warning for this line.
    >
    > 2 - When shifting by "shiftby" instead, it needs to compile code to
    > shift at the machine-code level, and places "64" in a register,
    > and executes an "unsigned left shift" of that amount. The CPU,
    > knowing that the operation is working on 64-bit values, only
    > uses the lower 6 bits of the shift amount. In this case, that
    > value is zero.
    >
    > I ran into (2) recently on code which worked just fine on a platform
    > which supported 64-bit ints, but failed on a system which only supported
    > 32-bit ints. In my case, I was splitting a value into two 32-bit values
    > to pass as parameters to a function. I did this by right-shifting the
    > value by 32 bits to get the high-order 32 bits. On the 64-bit-aware
    > platform, this worked just fine. On the 32-bit-only platform, the
    > shift of 32 bits was, at the CPU level, treated as a zero-bit shift
    > (the low-order 5 bits of the shift value being zero), causing the wrong
    > value for the "high 32 bits" parameter to be passed. (It should, of
    > course, been zero, as there were only the low-order 32 bits in the
    > value to begin with. Instead, it duplicated the low-order bits as
    > the high-order bits.)


    Wow! I've never seen this behavior. I would have assumed that shifting
    something too many times to the left always gets you zero and to the right
    either gets you zero or -1.

    Wow!

    --
    David T. Ashley ()
    http://www.e3ft.com (Consulting Home Page)
    http://www.dtashley.com (Personal Home Page)
    http://gpl.e3ft.com (GPL Publications and Projects)
     
    David T. Ashley, Jan 22, 2007
    #7
  8. krunalb

    Ben Pfaff Guest

    CBFalconer <> writes:

    n> krunalb wrote:
    >>
    >> I am trying to shift unsigned long long value by 64 bits and this
    >> is what i get

    >
    > Try thinking a moment. If you shift off 64 bits of a 64 bit
    > quantity, what do you have left?


    Undefined behavior.
    --
    "When in doubt, treat ``feature'' as a pejorative.
    (Think of a hundred-bladed Swiss army knife.)"
    --Kernighan and Plauger, _Software Tools_
     
    Ben Pfaff, Jan 22, 2007
    #8
  9. David T. Ashley wrote:

    > Wow! I've never seen this behavior. I would have assumed that shifting
    > something too many times to the left always gets you zero and to the right
    > either gets you zero or -1.


    On IA-32 processors (Pentium, Athlon etc. ), a hardware shift
    instruction uses only the lower five bit of the shift count, so (x <<
    n) produces the same result whether n == 32 or n == 0.
     
    christian.bau, Jan 22, 2007
    #9
  10. In article <> "David T. Ashley" <> writes:
    ....
    > Wow! I've never seen this behavior. I would have assumed that shifting
    > something too many times to the left always gets you zero and to the right
    > either gets you zero or -1.


    There are quite a few processors that use only the lower bits of the
    bit count if it is in a register. Moreover, there are also processors
    that do not have an arithmetic right shift. That is the reason that
    the standard states that:
    (1) Shifting by the width of the type or more is undefined.
    (2) Shifting a negative number to the right gives implementation-defined
    result.
    So (assuming a width of 32 for i, and i < 0):
    (i >> 16) >> 16
    can indeed yield -1 (2-s complement arithmetic shift), -0 (1-s complement
    arithmetic shift), -2147483647 (sign-magnitude arithmetic shift) or 0
    (logical shift)). (But I do not know whether sign-magnitude is actually
    allowed.)
    --
    dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
    home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
     
    Dik T. Winter, Jan 23, 2007
    #10
  11. "christian.bau" wrote:
    >
    > David T. Ashley wrote:
    >
    > > Wow! I've never seen this behavior. I would have assumed that shifting
    > > something too many times to the left always gets you zero and to the right
    > > either gets you zero or -1.

    >
    > On IA-32 processors (Pentium, Athlon etc. ), a hardware shift
    > instruction uses only the lower five bit of the shift count, so (x <<
    > n) produces the same result whether n == 32 or n == 0.


    If it used all 32 bits of the "shift by" value, imagine how long
    a 4 billion bit shift would take. :)

    (The only other option being to check that the value had non-zero
    bits in the upper part, and force zero/negative-one as the result
    immediately. However, as long as it's documented, the current
    behavior of only using the low 5 bits makes sense from both a
    hardware and software point of view.)

    Getting back to C, this is probably the exact reason why shifts of
    larger than the value is undefined. (Though "implementation
    defined" may have been more appropriate, I suppose there may be
    hardware in which the results are undefined at the hardware level.)

    --
    +-------------------------+--------------------+-----------------------+
    | Kenneth J. Brody | www.hvcomputer.com | #include |
    | kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
    +-------------------------+--------------------+-----------------------+
    Don't e-mail me at: <mailto:>
     
    Kenneth Brody, Jan 23, 2007
    #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. GGG
    Replies:
    10
    Views:
    12,569
    Donar
    Jul 6, 2006
  2. George Marsaglia

    Assigning unsigned long to unsigned long long

    George Marsaglia, Jul 8, 2003, in forum: C Programming
    Replies:
    1
    Views:
    684
    Eric Sosman
    Jul 8, 2003
  3. sarmin kho
    Replies:
    2
    Views:
    828
    A. Lloyd Flanagan
    Jun 15, 2004
  4. Miki Tebeka
    Replies:
    1
    Views:
    446
    Marcin 'Qrczak' Kowalczyk
    Jun 14, 2004
  5. Digital Puer

    extracting front bits from an unsigned long long?

    Digital Puer, Nov 11, 2005, in forum: C Programming
    Replies:
    36
    Views:
    1,343
    Mark McIntyre
    Nov 13, 2005
Loading...

Share This Page