В C / C ++, какой самый простой способ изменить порядок бит в байте? - PullRequest
93 голосов
/ 08 апреля 2010

Хотя существует несколько способов изменить порядок бит в байте, мне любопытно, что является "самым простым" для разработчика. И под реверсом я имею в виду:

1110 -> 0111
0010 -> 0100

Это похоже, но не дублирует этот вопрос PHP.

Это похоже, но не дублирует этот C вопрос. Этот вопрос задает самый простой метод для реализации разработчиком. «Лучший алгоритм» связан с производительностью памяти и процессора.

Ответы [ 30 ]

7 голосов
/ 18 июня 2014

Для константы, 8-битный вход, это не требует никакой памяти или процессора во время выполнения:

#define MSB2LSB(b) (((b)&1?128:0)|((b)&2?64:0)|((b)&4?32:0)|((b)&8?16:0)|((b)&16?8:0)|((b)&32?4:0)|((b)&64?2:0)|((b)&128?1:0))

Я использовал это для ARINC-429, где битовый порядок (порядковый номер) метки противоположен остальной части слова. Метка часто является константой и обычно восьмеричной. Например:

#define LABEL_HF_COMM MSB2LSB(0205)
6 голосов
/ 08 апреля 2010

Вас могут заинтересовать std::vector<bool> (то есть битовая упаковка) и std::bitset

Это должно быть самым простым, как требуется.

#include <iostream>
#include <bitset>
using namespace std;
int main() {
  bitset<8> bs = 5;
  bitset<8> rev;
  for(int ii=0; ii!= bs.size(); ++ii)
    rev[bs.size()-ii-1] = bs[ii];
  cerr << bs << " " << rev << endl;
}

Другие опции могут быть быстрее.

РЕДАКТИРОВАТЬ: я должен вам решение, используя std::vector<bool>

#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
using namespace std;
int main() {
  vector<bool> b{0,0,0,0,0,1,0,1};
  reverse(b.begin(), b.end());
  copy(b.begin(), b.end(), ostream_iterator<int>(cerr));
  cerr << endl;
}

Во втором примере требуется расширение c ++ 0x (для инициализации массива с {...}). Преимущество использования bitset или std::vector<bool> (или boost::dynamic_bitset) состоит в том, что вы не ограничены байтами или словами, но можете обратить произвольное количество битов.

НТН

3 голосов
/ 08 апреля 2010

Таблица поиска или

uint8_t rev_byte(uint8_t x) {
    uint8_t y;
    uint8_t m = 1;
    while (m) {
       y >>= 1;
       if (m&x) {
          y |= 0x80;
       }
       m <<=1;
    }
    return y;
}

редактировать

Посмотрите здесь для других решений, которые могут работать лучше для вас

2 голосов
/ 09 апреля 2010

более медленная, но более простая реализация:

static int swap_bit(unsigned char unit)
{
    /*
     * swap bit[7] and bit[0]
     */
    unit = (((((unit & 0x80) >> 7) ^ (unit & 0x01)) << 7) | (unit & 0x7f));
    unit = (((((unit & 0x80) >> 7) ^ (unit & 0x01))) | (unit & 0xfe));
    unit = (((((unit & 0x80) >> 7) ^ (unit & 0x01)) << 7) | (unit & 0x7f));

    /*
     * swap bit[6] and bit[1]
     */
    unit = (((((unit & 0x40) >> 5) ^ (unit & 0x02)) << 5) | (unit & 0xbf));
    unit = (((((unit & 0x40) >> 5) ^ (unit & 0x02))) | (unit & 0xfd));
    unit = (((((unit & 0x40) >> 5) ^ (unit & 0x02)) << 5) | (unit & 0xbf));

    /*
     * swap bit[5] and bit[2]
     */
    unit = (((((unit & 0x20) >> 3) ^ (unit & 0x04)) << 3) | (unit & 0xdf));
    unit = (((((unit & 0x20) >> 3) ^ (unit & 0x04))) | (unit & 0xfb));
    unit = (((((unit & 0x20) >> 3) ^ (unit & 0x04)) << 3) | (unit & 0xdf));

    /*
     * swap bit[4] and bit[3]
     */
    unit = (((((unit & 0x10) >> 1) ^ (unit & 0x08)) << 1) | (unit & 0xef));
    unit = (((((unit & 0x10) >> 1) ^ (unit & 0x08))) | (unit & 0xf7));
    unit = (((((unit & 0x10) >> 1) ^ (unit & 0x08)) << 1) | (unit & 0xef));

    return unit;
}
2 голосов
/ 09 апреля 2010

Перед реализацией любого алгоритмического решения проверьте язык ассемблера для используемой вами архитектуры ЦП. Ваша архитектура может включать инструкции, которые обрабатывают побитовые манипуляции, подобные этой (и что может быть проще, чем одна инструкция по сборке?).

Если такая инструкция недоступна, я бы предложил пойти по маршруту таблицы поиска. Вы можете написать скрипт / программу для генерации таблицы для вас, и операции поиска будут выполняться быстрее, чем любой из алгоритмов инвертирования битов, здесь (за счет необходимости хранить таблицу поиска где-нибудь).

2 голосов
/ 06 мая 2014

Может ли это быть быстрым решением?

int byte_to_be_reversed = 
    ((byte_to_be_reversed>>7)&0x01)|((byte_to_be_reversed>>5)&0x02)|      
    ((byte_to_be_reversed>>3)&0x04)|((byte_to_be_reversed>>1)&0x08)| 
    ((byte_to_be_reversed<<7)&0x80)|((byte_to_be_reversed<<5)&0x40)|
    ((byte_to_be_reversed<<3)&0x20)|((byte_to_be_reversed<<1)&0x10);

Избавляется от использования цикла for! но эксперты, пожалуйста, скажите мне, если это эффективно и быстрее?

2 голосов
/ 17 февраля 2018

Эта простая функция использует маску для проверки каждого бита входного байта и передачи его в сдвиговый выход:

char Reverse_Bits(char input)
{    
    char output = 0;

    for (unsigned char mask = 1; mask > 0; mask <<= 1)
    {
        output <<= 1;

        if (input & mask)
            output |= 1;
    }

    return output;
}
1 голос
/ 01 марта 2017

Этот основан на одном BobStein-VisiBone при условии

#define reverse_1byte(b)    ( ((uint8_t)b & 0b00000001) ? 0b10000000 : 0 ) | \
                            ( ((uint8_t)b & 0b00000010) ? 0b01000000 : 0 ) | \
                            ( ((uint8_t)b & 0b00000100) ? 0b00100000 : 0 ) | \
                            ( ((uint8_t)b & 0b00001000) ? 0b00010000 : 0 ) | \
                            ( ((uint8_t)b & 0b00010000) ? 0b00001000 : 0 ) | \
                            ( ((uint8_t)b & 0b00100000) ? 0b00000100 : 0 ) | \
                            ( ((uint8_t)b & 0b01000000) ? 0b00000010 : 0 ) | \
                            ( ((uint8_t)b & 0b10000000) ? 0b00000001 : 0 ) 

Мне это очень нравится, потому что компилятор автоматически выполняет всю работу за вас, поэтому не требует дополнительных ресурсов.

это также может быть расширено до 16-бит ...

#define reverse_2byte(b)    ( ((uint16_t)b & 0b0000000000000001) ? 0b1000000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000000010) ? 0b0100000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000000100) ? 0b0010000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000001000) ? 0b0001000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000010000) ? 0b0000100000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000100000) ? 0b0000010000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000001000000) ? 0b0000001000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000010000000) ? 0b0000000100000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000100000000) ? 0b0000000010000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000001000000000) ? 0b0000000001000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000010000000000) ? 0b0000000000100000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000100000000000) ? 0b0000000000010000 : 0 ) | \
                            ( ((uint16_t)b & 0b0001000000000000) ? 0b0000000000001000 : 0 ) | \
                            ( ((uint16_t)b & 0b0010000000000000) ? 0b0000000000000100 : 0 ) | \
                            ( ((uint16_t)b & 0b0100000000000000) ? 0b0000000000000010 : 0 ) | \
                            ( ((uint16_t)b & 0b1000000000000000) ? 0b0000000000000001 : 0 ) 
0 голосов
/ 04 мая 2019

Вот простое и удобочитаемое решение, переносимое на все совместимые платформы, в том числе с sizeof(char) == sizeof(int):

#include <limits.h>

unsigned char reverse(unsigned char c) {
    int shift;
    unsigned char result = 0;

    for (shift = 0; shift < CHAR_BIT; shift++) {
        result <<= 1;
        result |= c & 1;
        c >>= 1;
    }
    return result;
}
0 голосов
/ 15 февраля 2019

Я добавлю свое решение, поскольку пока не могу найти ничего подобного в ответах. Возможно, он немного перегружен, но генерирует таблицу подстановки, используя C ++ 14 std::index_sequence во время компиляции.

#include <array>
#include <utility>

constexpr unsigned long reverse(uint8_t value) {
    uint8_t result = 0;
    for (std::size_t i = 0, j = 7; i < 8; ++i, --j) {
        result |= ((value & (1 << j)) >> j) << i;
    }
    return result;
}

template<size_t... I>
constexpr auto make_lookup_table(std::index_sequence<I...>)
{
    return std::array<uint8_t, sizeof...(I)>{reverse(I)...};   
}

template<typename Indices = std::make_index_sequence<256>>
constexpr auto bit_reverse_lookup_table()
{
    return make_lookup_table(Indices{});
}

constexpr auto lookup = bit_reverse_lookup_table();

int main(int argc)
{
    return lookup[argc];
}

https://godbolt.org/z/cSuWhF

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...