ReadInt32 против ReadUInt32
Я возился с парсерами IP-пакетов, когда заметил что-то странное.
Когда дело доходит до разбора IP-адресов, в C#
private uint srcAddress;
// stuff
srcAddress = (uint)(binaryReader.ReadInt32());
делает трюк, так что вы думаете, что это VB.Net эквивалентны
Private srcAddress As UInteger
'' stuff
srcAddress = CUInt(binaryReader.ReadInt32())
сделал бы тоже самое. Это не так. Это:
srcAddress = reader.ReadUInt32()
однако будет.
Потребовалось время, чтобы обнаружить, но что я обнаружил - если что? Почему это?
1 ответ
VB.NET по умолчанию делает то, что C# не делает по умолчанию. Это всегда проверять на числовое переполнение. И это вызовет в вашем коде, что IP-адреса, последний бит которых равен 1 вместо 0, приведут к отрицательному числу и не могут быть преобразованы в UInteger. Тип данных, который может хранить только положительные 32-разрядные числа.
C# также имеет эту опцию, вам придется явно использовать ключевое слово check в вашем коде. Или используйте ту же опцию, которую проекты VB.NET включили по умолчанию: Project + Properties, вкладка Build, Advanced, отметьте флажок "Check for arithmetic overflow / underflow". Эта же опция в проекте VB.NET называется "Удалить проверки переполнения целых чисел", по умолчанию отключена.
Обратите внимание, как эти значения по умолчанию повлияли на синтаксис языков. В C# вы должны написать приведение для преобразования значения в несовместимый тип значения. В VB.NET нет необходимости, проверка во время выполнения избавит вас от проблем. Это очень плохая проблема, переполнение может привести к крайне плохим результатам. Не в вашем случае, это случается, IP-адрес действительно является неподписанным числом.
Не забывайте о другом измышлении об IP-адресах, сокеты были впервые изобретены на машинах Unix, работающих на LSD и процессорах с прямым порядком байтов. Обычно вы должны использовать IPAddress.NetworkToHostOrder(), чтобы получить адрес в правильном порядке. Который имеет только перегрузки, которые принимают целочисленный тип со знаком в качестве аргумента. Таким образом, использование ReadInt32() на самом деле правильно, предполагая, что это адрес IPv4, вы передаете его непосредственно в NetworkToHostOrder(). Нет страха переполнения.