Windows 11 США.
VB.NET, Как преобразовать 4 байта массива байтов в целочисленное значение?
Я могу понять, как сделать два байта, используя что-то вроде
IntValue = (mybyte(0) * 256) Or mybyte(1)
Итак, если mybyte(0) = 3
и mybyte(1) = 232
или шестнадцатеричный эквивалент 03E8, это будет int=1000.
Как я могу это сделать, если у меня есть 4 байта? mybyte(0)..(3)
.
Итак, если бы у меня было myByte(0) = 64
, а остальные байты (x)
равны 0 или шестнадцатеричному эквивалентному числу 40000000, это было бы равно 1 073 741 824.
Я попробовал другие предложения:
intval = Bitconverter.Toint32(mybyte, 0)
... все, что я получаю, это 64.
я тоже попробовал
Dim combined As UInteger = CType(((mybyte(0) << 24) Or (mybyte(1) << 16) Or (mybyte(2) << 8) Or (mybyte(3) << 0)), UInteger)
... все, что я получаю, это 64
ожидаю 1 073 741 824
Может быть, вы могли бы заполнить массив в обратном порядке?
Повторно добавлен тег C#. Первоначально ОП добавил его, и поэтому я предположил, что решение C# жизнеспособно (поскольку ОП предположительно может преобразовать его в VB.NET на основе их исходных тегов) и опубликовал соответствующий ответ.
Я пометил это как дубликат, но пропустил, что уже была попытка использовать BitConverter и получил неправильный результат. Как упоминается в коде ответа от Вольстада (и намекается в комментарии Эндрю Мортона), это похоже на проблему с порядком байтов.
Я не дал ответа, потому что 1) пост, который я упомянул в своем предыдущем комментарии, содержит хорошее объяснение побитовых операций, 2) у меня не было времени, 3) я не знал, что будет такая большая конкуренция дайте ответ (кто не любит хорошую конкуренцию)
@Itallmakescents Часто бывает интересно, что, казалось бы, простые вещи требуют дополнительных исследований. Например, освежить в памяти, что оператор <<
не расширяет результат.
Поскольку вы также изначально пометили теги C# (до того, как теги были отредактированы), вот решение на C# (которое, я предполагаю, вы можете легко преобразовать в VB.NET).
Использование BitConverter, о котором вы упомянули, действительно является правильным решением.
Следующий пример основан на документации MS: Как преобразовать массив байтов в int:
byte[] bytes = new byte[] { 64, 0, 0, 0 };
// If the system architecture is little-endian (that is, little end first),
// reverse the byte array.
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
int i = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("int: {0}", i);
Выход:
int: 1073741824
Обратите внимание на правильную обработку Endianness, чтобы убедиться, что байты обрабатываются в правильном порядке.
В этом и была проблема: мне пришлось перевернуть массив, чтобы получить правильный ответ. Спасибо всем откликнувшимся за помощь. Некоторые примеры других авторов также помогли лучше понять проблему.
@KenTaylor рад помочь и спасибо, что принял мой ответ. На всякий случай, если вы не в курсе, вы также можете проголосовать за мой ответ и любой другой полезный ответ (голосование и принятие — это отдельно). См.: Что мне делать, если кто-то отвечает на мой вопрос?.
В ВБ,
Dim i As Integer
Dim byts() As Byte = {1, 2, 3, 255}
If BitConverter.IsLittleEndian Then
Array.Reverse(byts)
i = BitConverter.ToInt32(byts, 0) ' i = 16909311
Else
i = BitConverter.ToInt32(byts, 0) ' i = -16580095
End If
Надеюсь, это поможет.
Другой подход...
Dim byts() As Byte = {1, 2, 3, 255}
If Not BitConverter.IsLittleEndian Then
Array.Reverse(byts)
End If
Dim i As Integer = 0
For Each b As Byte In byts
i = i << 8
i = i Or b
Next
Когда элементы mybyte
имеют тип Byte, выполнение mybyte(0)) << 24
приводит к созданию Byte, что нехорошо, поскольку все биты теряются. Этот оператор дает результат того же типа, что и левый операнд.
Вам нужно преобразовать каждый элемент в тот тип, который вы хотите получить в конце:
Dim a = CUInt(mybyte(0)) << 24 Or CUInt(mybyte(1)) << 16 Or CUInt(mybyte(2) << 8) Or mybyte(3)
(Арифметический битовый сдвиг имеет более высокий приоритет, чем побитовые операторы. Последний байт не нужно преобразовывать в другой тип.)
Была некоторая несогласованность в вопросе о том, нужно ли целое число или целое число без знака: измените вхождение CUInt
на CInt
, если первое.
Если вы используете операторы *
и +
, вы можете сделать
Dim b = (((mybyte(0) * 256 + mybyte(1)) * 256) + mybyte(2)) * 256 + mybyte(3)
или
Dim c = mybyte(0) * 16777216 + mybyte(1) * 65536 + mybyte(2) * 256 + mybyte(3)
которые работают без преобразований, поскольку множители 16777216, 65536 и 256 имеют тип Integer.
Или вы можете просто использовать:
Dim n = BitConverter.ToInt32(mybyte.Reverse().ToArray(), 0)
Наконец, если вы используете .NET Core 2.1 или новее, это очень просто:
Dim d = BinaryPrimitives.ReadInt32BigEndian(mybyte)
Документы: Класс BinaryPrimitives «Используйте эти помощники, когда вам нужно прочитать конкретный порядок байтов».
Этот вопрос похож на: Преобразование 16-битного регистра в два 8-байтовых с использованием vb.net в Visual Studio. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.