2015-06-28 2 views
0

Я читаю uint16 от датчика, подключенного к малине (руке). Я конвертирую данные из маленького конца в большой конец через:Бит-операция ИЛИ с добавлением

// result = 0A 0B 
// 0B 00 | 00 0A 
(result << 8) | (result >> 8); 

0A 0B 0B 0A впоследствии.

Но я также видел людей, использующих это:

(result << 8) + (result >> 8); 

Есть ли какие-либо преимущества использования дополнения? Я предполагаю, что нет никакого преимущества, это немного медленнее.

Существует большая разница, когда речь идет о сумме двух чисел, например:

EF10 = 0FF0 + 00FF != 0FF0 | 00FF = 0FFF 

Может быть, я ответил на мой собственный вопрос, но уже было бы неплохо, если бы кто-то мог оценить. Я бы не первый раз, когда я обманываю себя.

+1

Вы только спрашиваете о преимуществе, а также о различии? Эта последняя часть на самом деле не кажется вопросом. – harold

+0

Главным образом о преимуществе. Кажется, я знаю разницу, даже если я не могу объяснить это однозначно. Добавление должно использовать бит переноса для суммирования или просто сочетания. – aProgger

+1

В общем, я бы использовал битовые операторы для битовых операций и использовал арифметические операторы для арифметических операций, даже если они иногда приравниваются, а современные чипы довольно эффективны с точки зрения циклов выполнения. – Pynchia

ответ

2

Нет различий (или преимуществ, по крайней мере, не для современных процессоров), если комбинированные биты не перекрываются (другими словами, маска с левой стороны имеет нули для всех битов, установленных справа -hand сторона, и наоборот)

код, показанный здесь:

// result = 0A0B0C0D 0E0F0A0B 
// 0E0F0A0B 00000000 | 00000000 0A0B0C0D 
((result << 8) & 0xFF00) | (result >> 8); 

немного сбивает с толку - комментарий, кажется, подразумевает, что это 32-битное значение, но расчет предполагает 16-бит result

Вы получите разные значения r esults, например, если вы делаете что-то вроде этого:

value |= 128; 

против

value += 128; 

когда value уже имеет набор бит 7.

Обратите внимание, что по крайней мере в звоне:

#include <cstdint> 

uint32_t func1(uint32_t x) 
{ 
    return (x >> 8) | ((x << 8) & 0xFF000000); 
} 

uint32_t func2(uint32_t x) 
{ 
    return (x >> 8) + ((x << 8) & 0xFF000000); 
} 

генерируется Тот же самый код:

_Z5func1j:        # @_Z5func1j 
    movl %edi, %eax 
    shrl $8, %eax 
    shll $8, %edi 
    andl $-16777216, %edi  # imm = 0xFFFFFFFFFF000000 
    leal (%rdi,%rax), %eax 
    retq 

_Z5func2j:        # @_Z5func2j 
    movl %edi, %eax 
    shrl $8, %eax 
    shll $8, %edi 
    andl $-16777216, %edi  # imm = 0xFFFFFFFFFF000000 
    leal (%rdi,%rax), %eax 
    retq 
+0

да, ваше право. В настоящее время я работаю с датчиком, который обеспечивает 32 бит. простите за это. Отредактировал его. Но я совершенно не уверен, понимаю ли я ваш пример. – aProgger

+0

whay do '|' и '+' генерировать ** точно ** тот же код? Это разные операции и обычно дают разные результаты: 0x03 + 0x02 = 0x05, 0x03 | 0x02 = 0x03 – DrKoch

+0

@Mats Petersson. Теперь я понимаю ваш пример. Также благодарим вас за код сборки. Это очень интересно. – aProgger

3

Использование побитового или | проясняет, что это намерение, кто читает код, и это важный момент.

Я был бы удивлен различиями в скорости между двумя подходами.

Еще лучше было бы:

x = (x << 8) | (x >> 8); 

потому что нет необходимости маскировать левую часть (как входящие биты являются нулями).

В случае знакового целого, а не то, что приходит в при выполнении операции сдвига вправо на отрицательных значений зависит от реализации, поэтому переносимый код должен использовать

x = (x << 8) | ((x >> 8) & 0xFF); 

, чтобы понять, что байт-своп требуется операция.

+0

Обратите внимание, что 'x' является' uint16' (а не стандартным 'uint16_t') в вопросе. Ваши наблюдения, как правило, действительны, но почти наверняка не критичны для контекста вопроса. –

+0

@JonathanLeffler: спасибо, исправлено. – 6502

Смежные вопросы