Shift of shell bits producing different numbers

on my local bash machines at startup:

echo $((192 << 24)) 3221225472 

but for my built-in purposes the SHELL box loads. I get something else:

 echo $((192 << 24)) -1073741824 

It works when I left the shift to a smaller number. The attached device has a 64-bit version, where my local host is 32 bits.

To be clear, on a 32-bit machine, the value is positive; on a 64-bit machine, this is negative.

EDIT: This is on the embedded device, which is a 64-bit machine with SHELL . This does not happen when the left offset is 23.

 echo $((192 << 23)) 1610612736 echo $((192 << 24)) -1073741824 

On the local host, which is a 32 machine with BASH :

 echo $((192 << 55)) 6917529027641081856 echo $((192 << 56)) -4611686018427387904 
+4
source share
6 answers

POSIX ( here ) says: β€œOnly signed long integer arithmetic is required,” and in C, the length is at least 32 bits; that, as said, some shells explicitly choose a fixed width, for example, mksh uses 32-bit arithmetic and looks at the busybox source (math.h), it looks like they use only 64 bits, this is ENABLE_SH_MATH_SUPPORT_64 # define'd, regardless base system - 32/64 bit. If anyone knows better, say it!

+2
source

The binary representation of 192 is 11000000 . When you shift it, there are 24 places left, only the two bits that are set are the two most significant bits - the representation 11000000 00000000 00000000 00000000 . When a 32-bit system sees the most significant bit, it interprets it as a negative number in the "two additions" format. For a 64-bit system, the most significant bit is still zero, so it is interpreted as a positive number.

This is just an integer overflow on a 32 bit machine. You can expect the same behavior in C or any other language when using 32-bit integer types with 64-bit characters.

+3
source

Obviously, the result is crowded on the embedded device. Some calculations based on your results seem to support the hypothesis:

 $ echo 3221225472 - 1073741824 | bc -l 2147483648 $ echo 2^31 | bc -l 2147483648 

If you try more on your local computer, you will see that it overflows too!

 $ echo $((192 << 56)) -4611686018427387904 

EDIT: As you commented that you have Busybox 1.13.2, there is a chance that you are working on this issue. Upgrading can help!

+1
source

Well, it's just because of the number of bits that is represented by a number. 192 (0xc0) on shift becomes 0xc0000000. On a 32-bit machine, this is already a negative number, while on a 64-bit machine it is still in the range of a positive number.

+1
source

I think you almost answered your own question - the shell in a 32-bit machine presumably uses 32-bit signed integers for such arithmetic, whereas the shell in a 64-bit machine seems to use 64-bit signed integers numbers. With 32-bit integers, the maximum possible value is 2 ^ 31, so 3221225472 will lead to overflow.

+1
source

Got the same thing on my native Android built-in shell, but after running the busybox shell it works correctly.

 # echo $((192 << 23)) 1610612736 # echo $((192 << 23)) 1610612736 # echo $((192 << 24)) -1073741824 # busybox sh / # echo $((192 << 23)) 1610612736 / # echo $((192 << 24)) 3221225472 / # busybox 

using BusyBox v1.19.3

+1
source

All Articles