Reputation: 2345
in my local machines bash when I run:
echo $((192 << 24))
3221225472
but on my embedded targets busy box SHELL I get something else:
echo $((192 << 24))
-1073741824
it works when I left shift by a smaller number though. The embedded device is 64bit, where my local host is 32 bit.
Just to be clear, on the 32bit machine, the value is positive, on the 64 bit machine it's negative.
EDIT: This is on the embedded device which is 64 bit machine with SHELL. It doesn't happen when left shifting by 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
Upvotes: 5
Views: 13920
Reputation: 11
Got the same on on my native embedded android shell but after starting 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
Upvotes: 1
Reputation: 1357
POSIX (here) says "Only signed long integer arithmetic is required", and in C a long is at least 32 bits; that being said, some shells explicitly choose a fixed width, eg mksh uses 32 bits arithmetic, and peeking at the busybox' source (math.h) it seems like they only use 64 bits is ENABLE_SH_MATH_SUPPORT_64 is #define'd, regardless of whether the underlying system is 32/64 bits. If anyone knows better, speak up!
Upvotes: 2
Reputation: 123608
It's apparent that the result is overflowing on your embedded device. Some calculations based on your findings seem to substantiate the hypothesis:
$ echo 3221225472 - 1073741824 | bc -l
2147483648
$ echo 2^31 | bc -l
2147483648
If you try with more on your local machine, you'd figure that it'd overflow too!
$ echo $((192 << 56))
-4611686018427387904
EDIT: As you've commented that you're Busybox 1.13.2, there's a chance that you're running into this issue. Upgrading might help!
Upvotes: 1
Reputation: 16016
I think you almost answered your own question - the shell in the 32bit machine presumably uses 32bit signed integers for this kind of arithmetic, whereas the shell in the 64bit machine presumably uses 64bit signed integers. With 32bit signed integers, the max possible value is 2^31, so 3221225472 would result in an overflow.
Upvotes: 1
Reputation: 75568
Well it simply because of the number of bits the number is represented. 192 (0xc0) when shifted becomes 0xc0000000. On a 32 bit machine, it's already a negative number whereas on a 64bit machine, it's still on the range of a positive number.
Upvotes: 1
Reputation: 10786
The binary representation of 192
is 11000000
. When you shift it left 24 places, the only two bits which are set are the two most significant bits - the representation is 11000000 00000000 00000000 00000000
. When a 32 bit system sees the most significant bit set, it interprets it as a negative number in "two's complement" format. For a 64 bit system, the most significant bit is still zero, so it is interpreted as a positive number.
This is simply an integer overflow on the 32 bit machine. You could expect the same behavior in C or any other language when using 32 vs 64 bit signed integer types.
Upvotes: 3