Shifting unsigned long long values by 64 bits

K

krunalb

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
 
B

Barry

krunalb said:
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.
 
M

Mark F. Haigh

krunalb said:
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
(e-mail address removed)
 
M

mark_bluemel

krunalb said:
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...
 
K

Kenneth Brody

krunalb said:
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:[email protected]>
 
D

David T. Ashley

Kenneth Brody said:
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!
 
C

christian.bau

David said:
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.
 
D

Dik T. Winter

> 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.)
 
K

Kenneth Brody

christian.bau said:
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:[email protected]>
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top