Побитовые операции, объединяющие 3 байта в длину - PullRequest
0 голосов
/ 04 декабря 2011

Я пытаюсь объединить три байтовых значения в одно длинное значение, как это делает System.Drawing.Color.ToArgb ().

Я искал справочный исходный код, чтобы найти его и преобразовал в VB .NET:

Return CLng((CInt(red) << 16 Or CInt(green) << 8 Or blue Or CInt(alpha) << 24) And -1)

Конечно, все работает нормально, но я не совсем понимаю, почему альфа, сдвинутая на 24, является последней, а не первой (так что это будет в хорошем порядке 24, 16, 8). Я не очень разбираюсь в побитовых операциях. Кроме того, этот фрагмент кода работает для 4 байтов, что для меня избыточно, мне нужно всего три байта, и мне интересно, если Long по-прежнему требуется, когда байтов всего три, разве Integer не подойдет в этом случае?

Итак, мой вопрос: как мне переписать этот код для работы только с 3 параметрами? Нужно ли использовать Long? И, я знаю, что это глупо, но возможно ли сделать сдвиг байтов в порядке 16,8,0 вместо 16,8,0,24? Это действительно просто эстетика, но я ужасный перфекционист.

Заранее спасибо!

Aaron

Ответы [ 3 ]

1 голос
/ 04 декабря 2011

Вот несколько разных способов. Порядок ИЛИ не имеет значения. Я добавил несколько отладок, чтобы вы могли видеть результаты по ходу работы.

Private Sub Button1_Click(sender As System.Object, _
                          e As System.EventArgs) Handles Button1.Click

    Dim bar As Integer '32 bits

    'three byte values
    Dim x As Byte = 66
    Dim y As Byte = 65
    Dim z As Byte = 82

    'desired byte order
    '0xyz

    'one byte at a time
    bar = 0
    bar = bar Or (CInt(x) << 16)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))
    bar = bar Or (CInt(y) << 8)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))
    bar = bar Or (CInt(z) << 0) 'bar Or CInt(z)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))

    'or as single statement
    bar = 0 Or (CInt(x) << 16) Or (CInt(y) << 8) Or CInt(z)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))

    'in any order
    bar = 0 Or CInt(z) Or (CInt(y) << 8) Or (CInt(x) << 16)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))

    'check results
    Dim foo() As Byte = BitConverter.GetBytes(bar) 'get the individual bytes
    Array.Reverse(foo) 'reverse
    Debug.WriteLine(System.Text.ASCIIEncoding.ASCII.GetChars(foo, 1, 3))
End Sub
1 голос
/ 04 декабря 2011

Неважно, ИЛИ b - это то же значение, что и ИЛИ a.Оператор OR является коммутативным, как и операторы + и *.

Целое число может хранить значение очень хорошо, оно имеет 32 бита.Использование UInteger вместо этого может быть полезно для работы с альфа-значениями, превышающими 127, которые обращают значение в отрицательное значение.Что даст вам небольшую головную боль, когда вы попытаетесь прочитать альфа-значение обратно.Расширение знака приводит к большому значению, фиксированному с помощью AND-ing с 255. Long встречается в коде VB6, поскольку его тип Integer имеет только 16 битов, а не проблема в vb.net.

1 голос
/ 04 декабря 2011

Я не знаком с VB.NET, но в целом нет правильного или неправильного порядка подсчета смен.Это может быть 24, 16, 8, 0 или 16, 24, 0, 8 или любой другой порядок.

И изменение типа переменной: есть 8-битные, 16-битные и 32-битные переменные.Это означает, что вы должны определить 32-битный тип (long), чтобы иметь место для ваших трех байтов.Для удобства доступа оставьте 8 битов MSB равными 0, чтобы вы могли использовать его как 24-битное значение (0x00YYYYYY).

...