Search code examples
c#binaryreaderuint32

ReadInt32 vs. ReadUInt32


I was tinkering with IP packet 'parsers' when I noticed something odd.

When it came to parsing the IP addresses, in C#

private uint srcAddress; 
// stuff
srcAddress = (uint)(binaryReader.ReadInt32());

does the trick, so you'd think this VB.Net equivallent

Private srcAddress As UInteger
'' stuff
srcAddress = CUInt(binaryReader.ReadInt32())

would do the trick too. It doesn't. This :

srcAddress = reader.ReadUInt32()

however will.

Took some time to discover, but what have I dicovered -- if anything ? Why is this ?


Solution

  • VB.NET, by default, does something that C# doesn't do by default. It always check for numerical overflow. And that will trigger in your code, IP addresses whose last bit is 1 instead of 0 will produce a negative number and that cannot be converted to UInteger. A data type that can only store positive 32-bit numbers.

    C# has this option too, you'd have to explicitly use the checked keyword in your code. Or use the same option that VB.NET projects have turned on by default: Project + Properties, Build tab, Advanced, tick the "Check for arithmetic overflow/underflow" checkbox. The same option in VB.NET project is named "Remove integer overflow checks", off by default.

    Do note how these defaults affected the syntax of the languages as well. In C# you have to write a cast to convert a value to an incompatible value type. Not necessary in VB.NET, the runtime check keeps you out of trouble. It is very bad kind of trouble to have, overflow can produce drastically bad results. Not in your case, that happens, an IP address really is an unsigned number.

    Do keep the other quirk about IP-addresses in mind, sockets were first invented on Unix machines that were powered by LSD and big-endian processors. You must generally use IPAddress.NetworkToHostOrder() to get the address in the proper order. Which only has overloads that take a signed integer type as the argument. So using ReadInt32() is actually correct, assuming it is an IPv4 address, you pass that directly to NetworkToHostOrder(). No fear of overflow.