Хотя есть несколько способов изменить порядок следования битов в байтах, мне любопытно, что «проще всего» реализовать разработчику. Под реверсом я подразумеваю:
1110 -> 0111
0010 -> 0100
Это похоже, но не дублирует этот вопрос PHP.
Это похоже, но не дублирует этот вопрос C. Этот вопрос касается самого простого метода, который может реализовать разработчик. «Лучший алгоритм» касается памяти и производительности процессора.
c++
c
bit-manipulation
Натан
источник
источник
Ответы:
Если вы говорите об одном байте, поиск в таблице, вероятно, является лучшим вариантом, если по какой-либо причине у вас нет доступных 256 байтов.
источник
unsigned int rtable[] = {0x800, 0x4000, ...};
. Затем выбросьте сценарий и забудьте, что он у вас когда-либо был. Его писать намного быстрее, чем эквивалентный код C ++, и он будет запускаться только один раз, поэтому вы получаете время выполнения O (1) в вашем коде C ++.Это должно работать:
Сначала левые четыре бита меняются местами с правыми четырьмя битами. Затем меняются местами все соседние пары, а затем все смежные одиночные биты. Это приводит к обратному порядку.
источник
Я думаю, что поисковая таблица должна быть одним из самых простых методов. Однако вам не нужна полная таблица поиска.
Это довольно просто кодировать и проверять визуально.
В конечном итоге это может быть даже быстрее, чем полная таблица. Битовая арифметика дешевая, и таблица легко умещается в строке кэша.
источник
b0001(1) -> b1000(0x8)
,b0010(2) -> b0100(0x4)
,b1010(10) -> b0101(0x5)
. Видите узор? Это достаточно просто, чтобы вы могли вычислить это в уме (если вы умеете читать двоичный код, иначе вам понадобится бумага, чтобы решить это). Что касается скачка, то реверсирование 8-битного целого числа аналогично переворачиванию 4-битных частей и их замене местами; Я требую опыта и интуиции (или магии).См. Несколько способов решения этой проблемы. Очевидно, что копипастирование оттуда реализовать просто. знак равно
Например (на 32-битном процессоре):
Если под «простым в реализации» подразумевается что-то, что можно сделать без ссылки на экзамене или собеседовании, то наиболее безопасным вариантом будет, вероятно, неэффективное копирование битов один за другим в другую переменную в обратном порядке (уже показано в других ответах. ).
источник
Поскольку никто не опубликовал полное решение для поиска в таблице, вот мое:
источник
РЕДАКТИРОВАТЬ:
Преобразовал его в шаблон с необязательным битом
источник
sizeof(T)*8
наsizeof(T)*CHAR_BITS
.sizeof(T)*CHAR_BIT
наstd::numeric_limits<T>::digits
(спустя почти 4 года педантизма).CHAR_BIT
, нетCHAR_BITS
.Две строки:
или если у вас есть проблемы с частью "0b1":
"оригинал" - это байт, который нужно перевернуть. "reverse" - результат, инициализированный 0.
источник
Я бы использовал ассемблер, хотя, вероятно, не переносимый.
На многих языках ассемблера есть инструкции, как немного повернуть флаг переноса и повернуть флаг переноса в слово (или байт).
Алгоритм такой:
Код на языке высокого уровня для этого намного сложнее, потому что C и C ++ не поддерживают вращение для переноса и вращение для переноса. Флаг переноса должен быть смоделирован.
Изменить: например, язык ассемблера
источник
Я считаю следующее решение проще, чем другие алгоритмы, которые я видел здесь.
Он получает каждый бит байта и соответственно сдвигает его, начиная с первого до последнего.
Объяснение:
источник
Самый простой способ - это перебрать битовые позиции в цикле:
источник
CHAR_BIT
если предполагается,char
что у вас 8 бит?Вас могут заинтересовать
std::vector<bool>
(это битовая упаковка) иstd::bitset
По запросу он должен быть самым простым.
Другие варианты могут быть быстрее.
РЕДАКТИРОВАТЬ: Я должен вам решение, используя
std::vector<bool>
Во втором примере требуется расширение c ++ 0x (для инициализации массива
{...}
). Преимущество использования abitset
или astd::vector<bool>
(или aboost::dynamic_bitset
) в том, что вы не ограничены байтами или словами, но можете изменить произвольное количество бит.НТН
источник
std::vector<bool> b = { ... }; std::vector<bool> rb ( b.rbegin(), b.rend());
прямого использования обратных итераторов?Для очень ограниченного случая постоянного 8-битного ввода этот метод не требует затрат памяти или процессора во время выполнения:
Я использовал это для ARINC-429, где битовый порядок (порядок следования байтов) метки противоположен остальной части слова. Метка часто является постоянной и обычно восьмеричной.
Вот как я использовал его для определения константы, потому что спецификация определяет эту метку как восьмеричное число с прямым порядком байтов 205.
Еще примеры:
источник
Есть много способов перевернуть биты в зависимости от того, что вы подразумеваете под «простейшим способом».
Обратное вращение
Наверное, наиболее логично, состоит в том, чтобы повернуть байт при применении маски к первому биту
(n & 1)
:1) Поскольку длина неподписанного символа составляет 1 байт, что равно 8 битам, это означает, что мы будем сканировать каждый бит
while (byte_len--)
2) Сначала мы проверяем, находится ли b в крайнем правом положении с помощью
(b & 1)
; если это так, мы устанавливаем бит 1 на r с помощью|
и перемещаем его всего на 1 бит влево, умножая r на 2 с помощью(r << 1)
3) Затем мы делим наш символ без знака b на 2 с помощью,
b >>=1
чтобы стереть бит, расположенный в крайнем правом углу переменной b. Напоминаем, что b >> = 1; эквивалентно b / = 2;Обратный в одну строку
Это решение приписывается Ричу Шрёппелю в разделе Programming Hacks
1) Операция умножения (b * 0x0202020202ULL) создает пять отдельных копий 8-битного байтового шаблона для разветвления в 64-битное значение.
2) Операция И (& 0x010884422010ULL) выбирает биты, которые находятся в правильных (перевернутых) позициях относительно каждой 10-битной группы битов.
3) Вместе операции умножения и И копируют биты из исходного байта, поэтому каждая из них появляется только в одном из 10-битных наборов. Обратные позиции битов исходного байта совпадают с их относительными позициями в любом 10-битном наборе.
4) Последний шаг (% 0x3ff), который включает деление модуля на 2 ^ 10-1, имеет эффект слияния каждого набора из 10 бит (из позиций 0-9, 10-19, 20-29, ...) в 64-битном значении. Они не перекрываются, поэтому шаги сложения, лежащие в основе деления модуля, ведут себя как операции ИЛИ.
Разделяй и властвуй Решение
Это самый популярный ответ, и, несмотря на некоторые объяснения, я думаю, что для большинства людей трудно представить себе, что на самом деле означают 0xF0, 0xCC, 0xAA, 0x0F, 0x33 и 0x55.
Он не использует преимущества '0b', который является расширением GCC и включен в стандарт C ++ 14, выпущенный в декабре 2014 года, поэтому через некоторое время после этого ответа, датированного апрелем 2010 года
Пожалуйста, проверьте нижеприведенные фрагменты кода, чтобы лучше запомнить и понять это решение, в котором мы продвигаемся наполовину:
NB:
>> 4
это потому, что в 1 байте 8 битов, это беззнаковый символ, поэтому мы хотим взять вторую половину и так далее.Мы могли бы легко применить это решение к 4 байтам всего с двумя дополнительными строками и следуя той же логике. Поскольку обе маски дополняют друг друга, мы даже можем использовать ~ для переключения битов и экономии чернил:
[Только C ++] Отменить любой беззнаковый (шаблон)
Вышеупомянутую логику можно резюмировать с помощью цикла, который будет работать с любым типом беззнакового типа:
Попробуйте сами, включив указанную выше функцию:
Реверс с asm volatile
И последнее, но не менее важное: если простота означает меньше строк, почему бы не попробовать встроенную сборку?
Вы можете протестировать приведенный ниже фрагмент кода, добавив
-masm=intel
при компиляции:Пояснения построчно:
источник
Поиск по таблице или
редактировать
Поищите здесь другие решения, которые могут вам подойти.
источник
более медленная, но более простая реализация:
источник
Может ли это быть быстрым решением?
Избавляет от суеты использования цикла for! а специалисты подскажите, пожалуйста, эффективнее ли это и быстрее?
источник
Перед реализацией какого-либо алгоритмического решения проверьте язык ассемблера для любой архитектуры процессора, которую вы используете. Ваша архитектура может включать инструкции, которые обрабатывают подобные побитовые манипуляции (а что может быть проще одной инструкции сборки?).
Если такая инструкция недоступна, я бы предложил использовать маршрут таблицы поиска. Вы можете написать сценарий / программу для создания таблицы, и операции поиска будут быстрее, чем любой из приведенных здесь алгоритмов преобразования битов (за счет необходимости где-то хранить таблицу поиска).
источник
Эта простая функция использует маску для проверки каждого бита входного байта и передачи его в сдвигающийся выход:
источник
Это одна основана на одном BobStein-VisiBone при условии
Мне это очень нравится, потому что компилятор автоматически выполняет всю работу за вас, поэтому дополнительные ресурсы не требуются.
это также может быть расширено до 16 бит ...
источник
b
в круглые скобки, если это более сложное выражение, чем одно число, и, возможно, также переименовал бы макросREVERSE_BYTE
в качестве подсказки, что вы, вероятно, не хотите иметь там более сложное (время выполнения) выражение. Или сделайте это встроенной функцией. (Но в целом мне нравится, что это достаточно просто, чтобы вы могли легко сделать это по памяти с очень небольшой вероятностью ошибки.)Предполагая, что ваш компилятор допускает unsigned long long :
Обнаружено здесь
источник
Если вы используете небольшой микроконтроллер и вам нужно высокоскоростное решение с небольшой занимаемой площадью, это может быть решением. Его можно использовать для проекта C, но вам нужно добавить этот файл как файл ассемблера * .asm в ваш проект C. Инструкции: В проекте C добавьте это объявление:
Вызовите эту функцию из C
Это код, он подходит только для ядра 8051. В регистре процессора r0 находятся данные из byteInput . Код повернуть вправо r0 перекрестный перенос, а затем повернуть перенос влево до r1 . Повторите эту процедуру 8 раз для каждого бита. Затем регистр r1 возвращается функции c как byteOutput. В 8051 сердечник можно вращать только аккумулятором a .
ПЛЮСЫ: Небольшой размер, высокая скорость. МИНУСЫ: Это не многоразовый код, он предназначен только для 8051.
011101101-> носить
101101110 <-переносить
источник
обратный байт будет в регистре bl
источник
источник
uint8_t
1-битных полей немного некрасивым, так как сначала кажется, что это займет 8 бит, но затем в конце строки определяет его как только один бит. Я бы использовалunsigned b0:1
и т.д.источник
Я думаю это достаточно просто
или
источник
источник
Я добавлю свое решение, так как пока я не могу найти ничего подобного в ответах. Возможно, он немного переоценен, но он генерирует таблицу поиска с использованием C ++ 14
std::index_sequence
во время компиляции.https://godbolt.org/z/cSuWhF
источник
Вот простое и удобочитаемое решение, переносимое на все соответствующие платформы, в том числе с
sizeof(char) == sizeof(int)
:источник
Я знаю, что этот вопрос устарел, но я все же считаю, что тема актуальна для некоторых целей, и вот версия, которая работает очень хорошо и читается. Я не могу сказать, что он самый быстрый или самый эффективный, но он должен быть одним из самых чистых. Я также включил вспомогательную функцию для простого отображения битовых шаблонов. Эта функция использует некоторые стандартные библиотечные функции вместо написания собственного битового манипулятора.
И это дает следующий результат.
источник
Этот помог мне с набором массивов с точечной матрицей 8x8.
источник