Difference between C# and VB, simple add

Sometimes differences between C# and VB could be subtle, for example consider these very simple two snippets of code, what they will print?

   Sub Main()
      Console.WriteLine(
“Result is “ + Sum(Integer.MaxValue, 1))
   
End Sub
 
   
Public Function Sum(ByVal a As Integer, ByVal b As Integer)
      
Return a + b
   
End Function

   static void Main(string[] args) {
      
Console.WriteLine(“Result is “ + Sum(Int32.MaxValue, 1));
   }
 
   
public static Int32 Sum(Int32 a, Int32 b) {
      
return a + b;
   }

The first snipped written in VB throws a System.OverflowException, because the result of the operation cannot be stored into an integer value. The behavior of C# can be more surprising because it print Result is -2147483648 showing a result that is clearly wrong. This example shows that VB and C# have very different semantic even for basic operation. But what is the reason for such a different behavior? If we look at MSIL code we can see that VB compiler produces this code

    L_0002: ldarg.1 
    L_0003: add.ovf 
    L_0004: box int32 
 
As you can see the add operation gets translated with opcode add.ofv, where ofv means overflow. This particular operation throws an exception if the result of the operation will result in a overflow. C# generates this snippet.

    L_0002: ldarg.1 
    L_0003: add 
    L_0004: stloc.0

Generated MSIL is different because C# compiler use the add
opcode that will not check for an overflow. The question is: why such different behavior? VB.NET descends from VB6 where all arithmetic operations are checked, so this semantic is maintained even if for .NET version, C# descends from C++ where aritmetic operation does not check for an overflow. The primary reason is efficiency, let’s look at real IA32 code generated by the JIT compiler through disassembly window. This is the assembly generated for the add.ofv opcode (VB).

        Dim result As Integer = a + b
0000002e  mov         eax,ebx 
00000030  add         eax,dword ptr [ebp-40h] 
00000033  jno         0000003A 
00000035  call        79747E72 
0000003a  mov         dword ptr [ebp-44h],eax

After the add operation there is a jno opcode that means “Jump if not overflow“, if the operation will result in a overflow, the instruction does not jump and instruction at offset 35 calls a system routine that will throw the exception. The cost of checking overflow is a branch instruction after every arithmetic operation, for this reason C# compiler does not insert overflow check instruction for arithmetic operation. If you don’t like this, you can force C# compiler to insert overflow checking instruction with checked keyword

checked {
   
return a + b;

With the checked keyword we can choose to do checked operation only for specific parts of the code. VB is less flexible, because has a compiler operation that will disable overflow check for all the assembly, not showing the granularity of C#.

Alk.

Published by

Ricci Gian Maria

.Net programmer, User group and community enthusiast, programmer - aspiring architect - and guitar player :). Visual Studio ALM MVP

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.