完美解决VB中int to short溢出问题
工作笔记,英文烂没办法,如果不幸被你看到,请勿喷。。。
Summary:
- To unsigned type: just do And operator, or 2st method.
Eg. Dim a As Byte = CByte(300 And &HFF)
- To signed type: left shift n bits, then right shift n bits, which is to expand the signed bit. n = (sizeof(type1) - sizeof(type2)) * 8 or VB:use Len(New type) instead of sizeof(type)
Eg. Dim a As Short = CShort(34042 << 16 >> 16)
You can ignore the following information in case you don't want to know the detail.
int a = 34042;
short a1 = a;
You would got an error as follow:
Language compilers do not perform this conversion automatically because it can involve data loss. Instead, they perform the conversion only if a casting operator (in C#) or a conversion function (such as CType or CShort in Visual Basic) is used. Otherwise, they display a compiler error.
In C#, we can use a casting operator:
int a = 34042;
short a1 = (short)a;
In VB, we should use a conversion function:
Dim a As Integer = 100
Dim a1 As Short = CShort(a)
But issues occurred when the value is beyond the rang of short type in VB.
' Short: -32768 ~ 32767( 0FFFF8000H ~ 7FFFH)
Dim a As Integer = 34042
Dim a1 As Short = CShort(a)
In the 1st C# code, it works fine. But according to the value, how can we get -31494 from 34042? And why the VB code would catch an overflow exception(although it actually does)?
In fact, (short)a would generate IL:conv.i2 in C#. But CShort(a) would generate IL:conv.ovf.i2 in VB, and which might throw an overflow exception.
So, what we want to do is just to find out the rules of conversion.
conv.i2=Converts the value on top of the evaluation stack to int16, then extends (pads) it to int32.
Ok, let's follow it.
' Short: -32768 ~ 32767( FFFF8000H ~ 7FFFH)
Dim a As Integer = 34042
'Dim a1 As Short = CShort(a)
Dim a2 As Short = CShort(a And &HFFFF)
But unfortunately failed again, and got the same exception.
Actually, a And &HFFFF is still an integer but grater than Short.MaxValue, so it failed again.
Short is a 16-bit signed integer type so that it only contains 15 data-bit and 1 signed-bit.
Short.MaxValue and Short.MinValue:
00000000 00000000 01111111 11111111
11111111 11111111 10000000 00000000
So, after you do the "And" operator, you must expand another 16 bits according to the signed bit.
My solution is that: Left shift 16 bits, and then right shift 16 bits.
' Short: -32768 ~ 32767( FFFF8000H ~ 7FFFH)
Dim a As Integer = 34042
'Dim a1 As Short = CShort(a)
'Dim a2 As Short = CShort(a And &HFFFF)
Dim a3 As Short = CShort((a And &HFFFF) << 16 >> 16)
Let's see what happened.
a |
84FAH |
a And &HFFFF |
84FAH |
(a And &HFFFF) << 16 |
84FA 0000H |
(a And &HFFFF) << 16 >> 16 |
FFFF 84FAH |
Actually you can skip the And operator step.
Dim a3 As Short = CShort(a << 16 >> 16)
You can get these hex value by : Console.WriteLine("{0:X}", a) ...
Now it's all clear!
You can expand this method to other similar conversion, such as long to int( can use Fix()), long to short, etc.