views:

496

answers:

5

The next code works fine in C#:

    Int32 a, b;
    Int16 c;

    a = 0x7FFFFFFF;
    b = a & 0xFFFF;
    c = (Int16)b;

But this code crash with a OverflowException in VB.Net.

    Dim a, b As Int32
    Dim c As Int16

    a = &H7FFFFFFF
    b = a And &HFFFF
    c = CType(b, Int16)

Both codes seems the same to me. What is the difference and how can I get the C# code converted to VB.Net?

+2  A: 

Have you tried using DirectCast(b, Int16)? CType is not the same as a C# cast.

Here's an article comparing the performance of DirectCast and CType, as well as going into more detail to when either should be used.

Daniel May
`DirectCast(b, Int16)` causes compile error `Value of type 'Integer' cannot be converted to 'Short'.` http://msdn.microsoft.com/en-us/library/8sk75xak.aspx
MarkJ
+8  A: 

First up: My understanding of this is that CType(b, Int16) isn't the same as (Int16)b. One is a conversion of type (CType) and the other is a cast. (Int16)b equates to DirectCast(b, Int16) rather than CType(b, Int16).

The difference between the two (as noted on MSDN) is that CType succeeds so long as there is a valid conversion, however, DirectCast requires the run-time type of the object to be the same, and as such, all you're doing is telling the compiler at design time that this object is of that type rather than telling it to convert to that type.

See: http://msdn.microsoft.com/en-us/library/7k6y2h6x(VS.71).aspx

The underlying problem though is that you're trying to convert a 32 bit integer into a 16 bit integer which is... [I'm missing the word I need, perhaps someone can insert it here for me] lossy. Converting from 16 bit to 32 bit is allowed because it's lossless, converting from 32 bit to 16 bit is undefined. For why it works in C# you can see @Roman's answer - it relates to the fact that C# doesn't check the overflow.

The resulting value of &H7FFFFFFF And &HFFFF results in UInt16.MaxValue (65535) UInt16 runs from 0 to 65535, you're trying to cram that into Int16 which runs from -32768 through to 32767 which as you can see isn't going to work. Also the fact that this value might fit into a UInt16 is coincidental, adding two 32 bit integers and trying to cram them into a 16 bit integer (short) would frequently cause an overflow and thus I would say this is an inherently dangerous operation.

BenAlabaster
Regarding why it works in C# and throws exception in VB, see my answer below.
Roman Boiko
@Roman Thank you, that makes sense now I think about it.
BenAlabaster
SoMoS
A: 
?CType(b, Int16)
Constant expression not representable in type 'Short'.

?b
65535

?directcast(b, Int16)
Value of type 'Integer' cannot be converted to 'Short'.

?int16.TryParse(b.ToString(), c)
False
serhio
+8  A: 

From MSDN:

For the arithmetic, casting, or conversion operation to throw an OverflowException, the operation must occur in a checked context. By default, arithmetic operations and overflows in Visual Basic are checked; in C#, they are not. If the operation occurs in an unchecked context, the result is truncated by discarding any high-order bits that do not fit into the destination type.

EDIT: If you're going to port code from C# to VB.NET, you may be interested in differences between them. Also compare and explicitly set compiler settings to be the same as default settings in C# (when needed).

Roman Boiko
If you run the C# code, it doesn't cause an overflow. It just converts 65535 (Int32) to -1 (Int16)
MarkJ
MarkJ: that's exactly what is said in MSDN - in C# arithmetic operations are not checked, and overflow doesn't occur. In VB.NET they are checked by default, thus we get exception.
Roman Boiko
Ok, so as I see the point I create by myself some sort of "unchecked" keyword equivalent for VB.Net. I'm not porting code, I'm just looking for a solution to this question http://stackoverflow.com/questions/1873402/there-is-a-way-of-splitting-one-int32-into-two-int16
SoMoS
SoMoS: That question has a good accepted answer. I translated it to VB.NET, and posted as a new answer. It works without overflows. See http://stackoverflow.com/questions/1873402/there-is-a-way-of-splitting-one-int32-into-two-int16/1874916#1874916
Roman Boiko
It was the best answer available at that moment, this answer lead me to create this question.
SoMoS
For those who are interested in converting code from C# to VB.NET and vice versa: http://visualstudiomagazine.com/articles/2005/06/01/convert-between-vbnet-and-c.aspx
Roman Boiko
A: 

You can truncate this kind of overflow with a structure.

<StructLayout(LayoutKind.Explicit)> _
Public Structure int3216
    <FieldOffset(0)> Public i32 As Int32
    <FieldOffset(0)> Public i16high As Int16
    <FieldOffset(2)> Public i16low As Int16
End Structure

...

  Dim _i3216 As int3216
  _i3216.i32 = a And &HFFFF
  c = _i3216.i16low
Simon Karlsson