Чтение битов из памяти c ++, сдвиг и сохранение - PullRequest
0 голосов
/ 01 июля 2018

Я хочу прочитать 16 бит из памяти, сдвинуть их n раз в любом направлении, а затем сохранить обратно в той же позиции памяти ..

Предположим, что в памяти 0xfffaaa у меня есть: 0101111101100001 и я хочу сдвинуть его один раз вправо (>>1) Поэтому я объявляю переменную uint16_t, указывающую на 0xfffaaa.

После преобразования эта переменная содержит: 0110000101011111 (что составляет 24417 в десятичном виде). После правого сдвига: 0011000010101111 1 -> потерянный бит. Что хранится в памяти это: 1010111100110000 вместо: 0010111110110000 1 ---> потерянный бит.

Вот пример, как я пытаюсь это сделать ..

#include <bitset>
#include <iostream>
using namespace std;
int main(){
    volatile uint8_t *bitmap = (uint8_t *)malloc(2);
    bitmap[0] = 0b01011111;
    bitmap[1] = 0b01100001;

    cout << bitset<8>(bitmap[0]);
    cout << bitset<8>(bitmap[1]) << '\n' << '\n';

    uint16_t* p16 = (uint16_t*)bitmap;
    cout << bitset<16>(p16[0]) << '\n';
    p16[0]>>=1;
    cout << bitset<16>(p16[0]) << '\n' << '\n';

    cout << bitset<8>(bitmap[0]);
    cout << bitset<8>(bitmap[1]) << '\n';
   return 0;
}

И вывод консоли:

0101111101100001

0110000101011111
0011000010101111

1010111100110000

Как я могу сдвинуть бит так, как я хочу работать с uint16_t?

Ответы [ 3 ]

0 голосов
/ 01 июля 2018

Чтобы узнать, действительно ли это быстрее, так или иначе, вам нужно запустить профилировщик.

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

  1. Как @ 1201ProgramAlarm говорит:

    // получаем указатель uint16_t * p16 = (uint16_t *) растровое изображение; uint16_t v (* p16); v = (v >> 8) | (v << 8); // своп v >> = 1; * p16 = (v >> 8) | (v << 8); // переключаем обратно для сохранения в растровом изображении </p>

Это можно записать несколькими различными способами, и вы даже можете включить сдвиг в своп:

v = (v >> 9) | (v << 7);
  1. Вы не используете указатель p16

Поскольку вы можете выполнять своп и сдвиг одновременно, вы также можете напрямую использовать свой p8:

uint61_t v((bitmap[1] >> 9) | (bitmap[0] << 7));
bitmap[0] = v >> 8;
bitmap[1] = v; // C auto-and (i.e. (v & 0xFF) is not required)

Обратите внимание, что вы не можете оптимизировать намного больше, потому что когда вы изменяете растровое изображение, вы не можете перезагрузить данные после того, как они были изменены. Берегись этого.

Теперь эта сборка будет оптимизирована примерно так, хотя она может быть не самой быстрой (иногда возникают неожиданности, когда вы позволяете компилятору C / C ++ выполнять свою работу по оптимизации!)

mov ax, [ep]  ; get current value (16 bits)
xchg al, ah
shr ax, 1     ; shift by one unsigned
xchg al, ah
mov [ep], ax  ; save result

Для 32 и 64 битов в x86 есть инструкция swapb (тоже в 64 битах).

Обратите внимание, что чтение и запись байтов по одному могут быть такими же быстрыми, как чтение 16 битов и xchg -ing.

0 голосов
/ 01 июля 2018

Вы можете эффективно использовать объединение:

#include <bitset>
#include <iostream>
#include <algorithm>

using namespace std;

union joinbits
{
    uint16_t data;
    uint8_t  bits[2];
};

int main(){
    volatile uint8_t *bitmap = (uint8_t *)malloc(2);

    bitmap[0] = 0b01011111;
    bitmap[1] = 0b01100001;

    cout << bitset<8>(bitmap[0]);
    cout << bitset<8>(bitmap[1]) << '\n' << '\n';

    joinbits j;
    j.bits[1] =  bitmap[0];
    j.bits[0] =  bitmap[1];

    j.data >>= 1;

    bitmap[0] = j.bits[1];
    bitmap[1] = j.bits[0];

    cout << bitset<8>(bitmap[0]);
    cout << bitset<8>(bitmap[1]) << '\n';

    return 0;
}

Вывод:

0101111101100001                                                                                                                                               

0010111110110000                                                                                                                                               
0 голосов
/ 01 июля 2018

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

Поскольку сдвиг вправо будет перемещать биты из битовой карты [0] в битовую карту [1], вы можете извлечь данные в больший тип с умножением:

auto v16 = 256 * bitmap[0] | bitmap[1];
v16 >>= 1;
bitmap[0] = uint8_t(v16 / 256);
bitmap[1] = uint8_t(v16 & 255);

Альтернативно, используя только операции сдвига:

auto v16 = (bitmap[0] << 8) + bitmap[1];
v16 >>= 1;
bitmap[0] = uint8_t(v16 >> 8);
bitmap[1] = uint8_t(v16 & 0xFF);
...