LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Shift left operation (<<) behaves not as it should

System: Win32 (XP) with NI LW/CVI 2010 SP1

 

Code snippet 1:

 

unsigned char Bits = 32;

unsigned long ValidBits       = (1LU << Bits) - 1LU;

 

The result is 0 which is not what it should be.

 

Code snippet 2:

 

unsigned char Bits = 32;
unsigned long ValidBits       = (unsigned long)((1LLU << Bits) - 1LLU);

 

The result is 0xffffffff which is what is expected.

 

Its assumed that in case #1 the compiler uses
the assembly instruction "ROL" (barrel shifting, what goes out on the left returns on the right)
whilst all to my best knowledge any other mainstream c compiler

is using the assembly instruction "SHL" (linear shifting, what goes out on the left is dropped).

Unless otherwise advised i have to assume that this is a true bug
in the current implementation of the C programming language
and thus should be fixed. Please respond. Thank you.

0 Kudos
Message 1 of 9
(4,175 Views)

Shifting the same number or more bits than are in the left operand of the << operator has undefined behavior for left bitshift. Since a unsigned long is 32-bits, 1LU << 32 is has undefined behavior. In CVI it would appear that we do a ROL shift, but this is not behavior I would rely on. Any undefined behavior is subject to change. You will notice that 3LU << 31 produces 0x80000000 not 0x80000001.

 

 

National Instruments
0 Kudos
Message 2 of 9
(4,165 Views)

for any other c implementation i relied on the newly added digits on the right were always zero regardless if the number of shifts is smaller, equal or bigger than the number of digits in the shifting buffer. this assumed to be always true rule is only fullfillable with the SHL operation but not with ROL.

0 Kudos
Message 3 of 9
(4,146 Views)

ah, okay - looking a bit deeper using the no longer active document: http://www.winapi.co.kr/pds/doc/ISO-C-FDIS.1999-04.pdf

 

"6.5.7 Bitwise shift operators"

 

"The integer promotions are performed on each of the operands. The type of the result is
that of the promoted left operand. 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."

 

doing a "big thougths face" right now...

 

a "(1LU << 16) << 16" then should in theory do the job as well unless the compiler would falsely merge both operations into one of that form: "1LU << 32"

that would then be a violation of mathematics rule where some operations could be exchanged (like "A * 3 * 2 == A * 2 * 3").

 

at least it seemingly worked quite perfect in old NI LW/CVI 7.0. so thats sort of a compatiblility break.


C implementations should not break with their ancestors and not with the rule set of general math as well.

0 Kudos
Message 4 of 9
(4,144 Views)

verified with a derivate of the 2011 standard from the web: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

 

its still the same chapter number and seemingly still the same wording there.

thus it looks like ISO has currently still the very same "no-rules" policy on such a "against all rules of logic" topic since early days. 😉

0 Kudos
Message 5 of 9
(4,143 Views)

That's really strange...

Especially while NI is announcing the backward compatibility of CVI releases.

 

Well, maybe, this is not a full compatibility "break".

You can still run your old executable with the new run time engine but if you re-compile old code with the new release the behaviour will then change.

 

However, I wonder the motivation for changing such a low level behaviour.

I would also assume that a left shift is NOT rotational. I am sure that's what almost all programmers would think.

At least, that should be mentioned in the release notes..!

S. Eren BALCI
IMESTEK
0 Kudos
Message 6 of 9
(4,132 Views)

I'm not aware of there having been any change in the shifting behavior.

 

Alexander, you mentioned that in CVI 7.0, this worked perfectly. What exactly do you mean by that? Did you mean that the result of your code snippet 1 was not 0? Or were you referring to (1LU << 16) << 16? When I tested both expressions in 7.0, the result was 0, as it still is in the latest version of CVI.

 

Luis

0 Kudos
Message 7 of 9
(4,121 Views)

the initial and only problem for me was/is that "1LU << N" with N=32 run on 2010 SP1 produces something unexpected and not seen in 7.0.

the "(1LU << 16) << 16" was only an additional thought from me on shift operations in general.

 

meanwhile (without further testing) i came to the opinion that there are three possible options:

- its done using a ROL.

- its not done at all if N exceeding 31.

- its done with "N % 32 = 0".

 

the main problem is that it has changed.

my personal work around now is a macro function alike helper whose right side looks basically like this:

  (n >= sizeof(unsigned int) * 8)? 0LU: (x << n)

0 Kudos
Message 8 of 9
(4,104 Views)

Hello Alex,

I just tested your code snippet 1 on various releases from CVI6.0 up to 2010SP1 and the result was validBits = 0 on all of them; again, with the code in your last message I always had validBits = 1 so it seems that no change have been during time.

Are you sure that your CVI7 code was exactly like your code snippet?



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 9 of 9
(4,098 Views)