473,385 Members | 1,769 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Queer! right-shifting more than a type's width

Ok, what is this supposed to print:

#include <stdio.h>
#include <stdint.h>

int
main (void)
{
uint32_t r, s;

s = 33;
r = (uint32_t)1 << s;
printf("r = %u\n", r);

return 0;
}

I have been programming in C for several years (and doing a lot of
low-level stuff that require bit manipulations) but this I didn't
expect!!!!

It turns out that the number printed is "2"!!!

How on earth is the "<<" operator defined? It is certainly not defined
as a shift, neither as a "multiplication". I'm totally confused!

/npat
Nov 14 '05 #1
8 1626
Nick Patavalis <np**@efault.net> writes:
uint32_t r, s;

s = 33;
r = (uint32_t)1 << s;


Behavior of << and >> is undefined when the right operand is
greater than or equal to the width of the left operand. See
C99 6.5.7#3.
--
Ben Pfaff
email: bl*@cs.stanford.edu
web: http://benpfaff.org
Nov 14 '05 #2
>Ok, what is this supposed to print:

There is nothing that this is *NOT* supposed to print.
Invoking undefined behavior allows any behavior at all.

#include <stdio.h>
#include <stdint.h>

int
main (void)
{
uint32_t r, s;

s = 33;
r = (uint32_t)1 << s;
Shifting by more than the width of the type invokes the
wrath of undefined behavior.
printf("r = %u\n", r);

return 0;
}

I have been programming in C for several years (and doing a lot of
low-level stuff that require bit manipulations) but this I didn't
expect!!!!

It turns out that the number printed is "2"!!!
If you've ever looked at the definitions of shift instructions in
assembly language (i386 in particular, but it's not the only one
like this), you might notice that some of those involving a variable
shift count (usually in a register) only pay attention to a limited
number of bits in that register. After all, there's not much point
in actually shifting an integer 1073741824 times, and it's likely
to lock out interrupts for way too long.

If a << b is implemented as a << (b % 32) where a is a
32-bit integer, you get the observed behavior.
How on earth is the "<<" operator defined? It is certainly not defined
as a shift, neither as a "multiplication". I'm totally confused!


It is not defined at all when you hand it numbers out of range.

Gordon L. Burditt
Nov 14 '05 #3
On 2004-08-09, Gordon Burditt <go***********@burditt.org> wrote:

If you've ever looked at the definitions of shift instructions in
assembly language (i386 in particular, but it's not the only one
like this), you might notice that some of those involving a variable
shift count (usually in a register) only pay attention to a limited
number of bits in that register. After all, there's not much point
in actually shifting an integer 1073741824 times, and it's likely
to lock out interrupts for way too long.


If I remember correctly, it is not the same for ARMs (which I have
been dealing with recently). In this architecture shifting more than
the width of the register will give you zero. I'm not sure though, and
I don't have th ARM-ARM at nearby.

But of course you 're right: It is an undefined behavior in any
case. What makes things more "peculiar" is that two very similar
programs might behave very differently even when compiled for the same
architecture. When I first observed this, the program was doing
something like this:

#define cond(fc) if ( (1UL << (fc)) & (mask) )
#define cond_enable(fc) do { mask |= 1UL << (fc); } while (0)
#define cond_disable(fc) do { mask &= ~(1UL << (fc)); } while (0)

.... several conditions were defined ....

#define NEVER 32
#define C1 1
#define C2 2
#define C3 NEVER
#define C4 4

.... and springled inside the code stuff like this ....

cond(C1) { printf("This only if C1 is enabled\n"); }
cond(C3) { printf("This never\n"); }

It worked fine, until someone decided to use variables for the
condition-bits, instead of constants:

int c5 = 5;
int c6 = 6;
int c7 = 7;
...
c6 = NEVER
...
cond(c6) { printf("This never\n"); }

I think you 're getting the picture.

Anyway thanks for your reply (all of you).
/npat
Nov 14 '05 #4
On Mon, 9 Aug 2004 07:11:50 +0000 (UTC),
Nick Patavalis <np**@efault.net> wrote
in Msg. <sl*****************@gray.efault.net>
But of course you 're right: It is an undefined behavior in any
case. What makes things more "peculiar" is that two very similar
programs might behave very differently even when compiled for the same
architecture.


Exactly that's what undefined behavior is all about, which is why it is to
be avoided like the plague. You need not even compare "very similar"
progams; one and the same program might behave differently when run
repeatedly.

--Daniel

--
"With me is nothing wrong! And with you?" (from r.a.m.p)
Nov 14 '05 #5
Nick Patavalis wrote:
Ok, what is this supposed to print:

#include <stdio.h>
#include <stdint.h>

int
main (void)
{
uint32_t r, s;

s = 33;
r = (uint32_t)1 << s;
printf("r = %u\n", r);

return 0;
}

I have been programming in C for several years (and doing a lot of
low-level stuff that require bit manipulations) but this I didn't
expect!!!!

It turns out that the number printed is "2"!!!

How on earth is the "<<" operator defined? It is certainly not defined
as a shift, neither as a "multiplication". I'm totally confused!


How many years is several? Can you imagine any association between
Shift and Rotate? Clearly (not?) 'r = (uint32_t)1 << 31' is the
widest shift you can expect to work in C.

00000000 00000000 00000000 00000001

...becomes..

10000000 00000000 00000000 00000000

Wider is Undefined Behaviour. Having said that, if shifting 32
wraps, yielding the original pattern..

00000000 00000000 00000000 00000001

...and shifting 33 yields..

00000000 00000000 00000000 00000010

...I, for one, would not be totally confused.
--
Joe Wright mailto:jo********@comcast.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #6
On 2004-08-10, Joe Wright <jo********@comcast.net> wrote:

How many years is several? Can you imagine any association between
Shift and Rotate?

I can, but what we're witnessing is definitely *not* a rotate.
Clearly (not?) 'r = (uint32_t)1 << 31' is the
widest shift you can expect to work in C.


I understand that this is how left-shift is *defined*. But it could
easily be defined having shifts larger than the type-width result to
zero. Come to think of it, this is what happens with
constants. Actually your example is *wrong*:

r = (uint32_t)1 << 31

yields:

00000000 00000000 00000000 00000001

while, all of the following:

r = (uint32_t)1 << 32
r = (uint32_t)1 << 33
r = (uint32_t)1 << 34

yield

00000000 00000000 00000000 00000000

The 'problem' appears *only* when the code is written like this:

s = 32;
r = (uint32_t)1 << s;

And what really happens, is that the compiler simply emits the
architecture's left-shift instruction (*not* the rotate instruction),
regardless of the value of "k". The problem is that for *some* 32bit
architectures the left-shift instruction only considers bits bit 4:0
of the register-operand, and *this* explains the behavior
observed. For other architectures the shifter ORs the remaining
operand-register bits together, and if the OR's result is non-zero, it
zeroes the shift's result (guaranteeing this way a more "consistent"
behavior).

The compiler is allowed to *simply* emit the architectural shift
instruction, because the standard explicitly makes shifts more than
the type-width undefined.

In the examples above (with the literals), the compiler has to emit no
shift instructions whatsoever; it simply performs the shift
*internally*. And it this case it does it using the "consistent" way.

/npat
Nov 14 '05 #7
Nick Patavalis <np**@efault.net> writes:
On 2004-08-10, Joe Wright <jo********@comcast.net> wrote:

How many years is several? Can you imagine any association between
Shift and Rotate?

I can, but what we're witnessing is definitely *not* a rotate.
Clearly (not?) 'r = (uint32_t)1 << 31' is the
widest shift you can expect to work in C.


I understand that this is how left-shift is *defined*. But it could
easily be defined having shifts larger than the type-width result to
zero. Come to think of it, this is what happens with
constants. Actually your example is *wrong*:

r = (uint32_t)1 << 31

yields:

00000000 00000000 00000000 00000001


Are you showing the high-order bit at the far right? The
result of (uint32_t)1 << 31 is 0x80000000 or

10000000 00000000 00000000 00000000

in normal binary (high bit first) notation.

[...] The compiler is allowed to *simply* emit the architectural shift
instruction, because the standard explicitly makes shifts more than
the type-width undefined.


More than or equal to.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #8
On 2004-08-10, Keith Thompson <ks***@mib.org> wrote:
Nick Patavalis <np**@efault.net> writes:

r = (uint32_t)1 << 31

yields:

00000000 00000000 00000000 00000001
Are you showing the high-order bit at the far right?


No intel has not deranged my mind *that* much :) this is just a typo.
The result of (uint32_t)1 << 31 is 0x80000000 or

10000000 00000000 00000000 00000000

in normal binary (high bit first) notation.

Obviously!
[...]
The compiler is allowed to *simply* emit the architectural shift
instruction, because the standard explicitly makes shifts more than
the type-width undefined.


More than or equal to.


Once more I stand corrected.

Thanks for your corrections.
/npat
Nov 14 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: aurora | last post by:
Let's stop discussing about the perl-python non-sense. It is so boring. For a break, just visit Mr Xah Lee's personal page (http://xahlee.org/PageTwo_dir/Personal_dir/xah.html). You'll find lot...
7
by: Ekim | last post by:
hy, I've a question concerning exception-handling in c++: is there a possibility to catch any exception (I know one can do that by "catch(...)") and display its default-error-message (like in...
87
by: Frances Del Rio | last post by:
is there a non-breaking hyphen in HTML?? for example, so a phone no. falls all on one line.. as in.. 1-800-444-5454... (and is not broken into two lines if phone no. occurs near end of a...
7
by: K. Crothers | last post by:
I administer a mechanical engineering database. I need to build a query which uses the results from a subquery as its input or criterion. I am attempting to find all of the component parts of...
16
by: Ekim | last post by:
hello, I'm allocating a byte-Array in C# with byte byteArray = new byte; Now I want to pass this byte-Array to a managed C++-function by reference, so that I'm able to change the content of the...
6
by: bob lambert | last post by:
Help, I have vb.net std 2002, have a windows forms app and am debugging code behind it. I think I am viewing the source, I set the project to debug (as opposed to release), I start the...
1
by: sanjaymeher | last post by:
Copy paste and run the example now remove the comment /*test2();*/ in main function ... Its not working .. Whyyyy ?? Behavior is really queer !!!! I know the method "int...
1
by: qweer | last post by:
I want download all contacts from my mobile phone to my computer. I have to use usb (or bluetooth) interface and syncML. Someone has any examples or tutorials, how could I do this. (how can use...
2
by: Marcus Schaefer | last post by:
Hello, I have a queer problem in my project (Visual Basic Express 2005): When I create a new Instance of one of my classes dim data as new CData(fname) <-- crash ! Dim frm as new...
77
by: Ville Vainio | last post by:
I tried to clear a list today (which I do rather rarely, considering that just doing l = works most of the time) and was shocked, SHOCKED to notice that there is no clear() method. Dicts have it,...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.