简体   繁体   English

在 C/C++ 中,反转字节中位顺序的最简单方法是什么?

[英]In C/C++ what's the simplest way to reverse the order of bits in a byte?

While there are multiple ways to reverse bit order in a byte, I'm curious as to what is the "simplest" for a developer to implement.虽然有多种方法可以反转字节中的位顺序,但我很好奇开发人员实现的“最简单”方法是什么。 And by reversing I mean:反过来我的意思是:

1110 -> 0111
0010 -> 0100

This is similar to, but not a duplicate of this PHP question. 与 PHP 问题类似,但不是重复的。

This is similar to, but not a duplicate of this C question. 与 C 问题类似,但不是重复的。 This question is asking for the easiest method to implement by a developer.这个问题要求开发人员实现最简单的方法。 The "Best Algorithm" is concerned with memory and cpu performance. “最佳算法”与 memory 和 cpu 性能有关。

This should work:这应该有效:

unsigned char reverse(unsigned char b) {
   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
   b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
   return b;
}

First the left four bits are swapped with the right four bits.首先左四位与右四位交换。 Then all adjacent pairs are swapped and then all adjacent single bits.然后交换所有相邻的对,然后交换所有相邻的单个位。 This results in a reversed order.这导致相反的顺序。

I think a lookup table has to be one of the simplest methods.我认为查找表必须是最简单的方法之一。 However, you don't need a full lookup table.但是,您不需要完整的查找表。

//Index 1==0b0001 => 0b1000
//Index 7==0b0111 => 0b1110
//etc
static unsigned char lookup[16] = {
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };

uint8_t reverse(uint8_t n) {
   // Reverse the top and bottom nibble then swap them.
   return (lookup[n&0b1111] << 4) | lookup[n>>4];
}

// Detailed breakdown of the math
//  + lookup reverse of bottom nibble
//  |       + grab bottom nibble
//  |       |        + move bottom result into top nibble
//  |       |        |     + combine the bottom and top results 
//  |       |        |     | + lookup reverse of top nibble
//  |       |        |     | |       + grab top nibble
//  V       V        V     V V       V
// (lookup[n&0b1111] << 4) | lookup[n>>4]

This fairly simple to code and verify visually.这相当容易编码和视觉验证。
Ultimately this might even be faster than a full table.最终,这甚至可能比全表更快。 The bit arith is cheap and the table easily fits on a cache line.位算法很便宜,并且该表很容易适合缓存行。

如果您谈论的是单个字节,那么查找表可能是最好的选择,除非由于某种原因您没有 256 个字节可用。

See the bit twiddling hacks for many solutions.有关许多解决方案,请参阅bit twiddling hacks Copypasting from there is obviously simple to implement.从那里复制粘贴显然很容易实现。 =) =)

For example (on a 32-bit CPU):例如(在 32 位 CPU 上):

uint8_t b = byte_to_reverse;
b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;

If by “simple to implement” one means something that can be done without a reference in an exam or job interview, then the safest bet is probably the inefficient copying of bits one by one into another variable in reverse order (already shown in other answers).如果“简单实施”意味着在考试或工作面试中无需参考就可以完成的事情,那么最安全的选择可能是将比特以相反的顺序一个接一个地低效复制到另一个变量中(已在其他答案中显示) )。

Since nobody posted a complete table lookup solution, here is mine:由于没有人发布完整的查表解决方案,这里是我的:

unsigned char reverse_byte(unsigned char x)
{
    static const unsigned char table[] = {
        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    };
    return table[x];
}
template <typename T>
T reverse(T n, size_t b = sizeof(T) * CHAR_BIT)
{
    assert(b <= std::numeric_limits<T>::digits);

    T rv = 0;

    for (size_t i = 0; i < b; ++i, n >>= 1) {
        rv = (rv << 1) | (n & 0x01);
    }

    return rv;
}

EDIT:编辑:

Converted it to a template with the optional bitcount使用可选的 bitcount 将其转换为模板

Two lines:两行:

for(i=0;i<8;i++)
     reversed |= ((original>>i) & 0b1)<<(7-i);

or in case you have issues with the "0b1" part:或者如果您对“0b1”部分有问题:

for(i=0;i<8;i++)
     reversed |= ((original>>i) & 1)<<(7-i);

"original" is the byte you want to reverse. “原始”是您要反转的字节。 "reversed" is the result, initialized to 0. “反转”是结果,初始化为 0。

Although probably not portable, I would use assembly language.虽然可能不可移植,但我会使用汇编语言。
Many assembly languages have instructions to rotate a bit into the carry flag and to rotate the carry flag into the word (or byte).许多汇编语言都有将位旋转到进位标志并将进位标志旋转到字(或字节)的指令。

The algorithm is:算法是:

for each bit in the data type:
  rotate bit into carry flag
  rotate carry flag into destination.
end-for

The high level language code for this is much more complicated, because C and C++ do not support rotating to carry and rotating from carry.用于此的高级语言代码要复杂得多,因为 C 和 C++ 不支持旋转进位和从进位旋转。 The carry flag has to modeled.进位标志必须建模。

Edit: Assembly language for example编辑:例如汇编语言

;  Enter with value to reverse in R0.
;  Assume 8 bits per byte and byte is the native processor type.
   LODI, R2  8       ; Set up the bit counter
Loop:
   RRC, R0           ; Rotate R0 right into the carry bit.
   RLC, R1           ; Rotate R1 left, then append carry bit.
   DJNZ, R2  Loop    ; Decrement R2 and jump if non-zero to "loop"
   LODR, R0  R1      ; Move result into R0.

I find the following solution simpler than the other bit fiddling algorithms I've seen in here.我发现以下解决方案比我在这里看到的其他位摆弄算法更简单。

unsigned char reverse_byte(char a)
{

  return ((a & 0x1)  << 7) | ((a & 0x2)  << 5) |
         ((a & 0x4)  << 3) | ((a & 0x8)  << 1) |
         ((a & 0x10) >> 1) | ((a & 0x20) >> 3) |
         ((a & 0x40) >> 5) | ((a & 0x80) >> 7);
}

It gets every bit in the byte, and shifts it accordingly, starting from the first to the last.它获取字节中的每一位,并相应地移动它,从第一个到最后一个。

Explanation:解释:

   ((a & 0x1) << 7) //get first bit on the right and shift it into the first left position 
 | ((a & 0x2) << 5) //add it to the second bit and shift it into the second left position
  //and so on

There are many ways to reverse bits depending on what you mean the "simplest way".根据您的意思是“最简单的方法”,有很多方法可以反转位。


Reverse by Rotation旋转反转

Probably the most logical, consists in rotating the byte while applying a mask on the first bit (n & 1) :可能是最合乎逻辑的,包括在对第一位(n & 1)应用掩码的同时旋转字节:

unsigned char reverse_bits(unsigned char b)
{
    unsigned char   r = 0;
    unsigned        byte_len = 8;

    while (byte_len--) {
        r = (r << 1) | (b & 1);
        b >>= 1;
    }
    return r;
}
  1. As the length of an unsigner char is 1 byte, which is equal to 8 bits, it means we will scan each bit while (byte_len--)由于 unsigner char 的长度为 1 个字节,等于 8 位,这意味着我们将while (byte_len--)

  2. We first check if b as a bit on the extreme right with (b & 1) ;我们首先用(b & 1)检查 b 是否在最右边; if so we set bit 1 on r with |如果是这样,我们在 r 上设置位 1 | and move it just 1 bit to the left by multiplying r by 2 with (r << 1)并通过将 r 乘以 2 与(r << 1)将其向左移动 1 位

  3. Then we divide our unsigned char b by 2 with b >>=1 to erase the bit located at the extreme right of variable b.然后我们用b >>=1除以 2 的无符号字符 b 以擦除位于变量 b 最右侧的位。 As a reminder, b >>= 1;提醒一下,b >>= 1; is equivalent to b /= 2;相当于 b /= 2;


Reverse in One Line一行反转

This solution is attributed to Rich Schroeppel in the Programming Hacks section此解决方案归功于“编程黑客”部分中的 Rich Schroeppel

unsigned char reverse_bits3(unsigned char b)
{
    return (b * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff;
}
  1. The multiply operation (b * 0x0202020202ULL) creates five separate copies of the 8-bit byte pattern to fan-out into a 64-bit value.乘法运算 (b * 0x0202020202ULL) 创建 8 位字节模式的五个单独副本,以扇出为 64 位值。

  2. The AND operation (& 0x010884422010ULL) selects the bits that are in the correct (reversed) positions, relative to each 10-bit groups of bits. AND 运算 (& 0x010884422010ULL) 选择相对于每个 10 位位组处于正确(反转)位置的位。

  3. Together the multiply and the AND operations copy the bits from the original byte so they each appear in only one of the 10-bit sets.乘法和与运算一起从原始字节复制位,因此它们每个都只出现在 10 位集合中的一个中。 The reversed positions of the bits from the original byte coincide with their relative positions within any 10-bit set.与原始字节相反的位的位置与它们在任何 10 位集合中的相对位置一致。

  4. The last step (% 0x3ff), which involves modulus division by 2^10 - 1 has the effect of merging together each set of 10 bits (from positions 0-9, 10-19, 20-29, ...) in the 64-bit value.最后一步 (% 0x3ff) 涉及模数除以 2^10 - 1 的作用是将每组 10 位(从位置 0-9、10-19、20-29、...)合并在一起。 64 位值。 They do not overlap, so the addition steps underlying the modulus division behave like OR operations.它们不重叠,因此模数除法基础的加法步骤的行为类似于 OR 运算。


Divide and Conquer Solution分而治之的解决方案

unsigned char reverse(unsigned char b) {
   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
   b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
   return b;
}

This is the most upvoted answer and despite some explanations, I think that for most people it feels difficult to visualize whats 0xF0, 0xCC, 0xAA, 0x0F, 0x33 and 0x55 truly means.这是最受欢迎的答案,尽管有一些解释,但我认为对于大多数人来说,很难想象 0xF0、0xCC、0xAA、0x0F、0x33 和 0x55 的真正含义。

It does not take advantage of '0b' which is a GCC extension and is included since the C++14 standard, release in December 2014, so a while after this answer dating from April 2010它没有利用'0b',它是一个GCC 扩展,自 2014 年 12 月发布的 C++14 标准以来就包含在内,所以在这个答案可以追溯到 2010 年 4 月之后的一段时间

Integer constants can be written as binary constants, consisting of a sequence of '0' and '1' digits, prefixed by '0b' or '0B'.整数常量可以写成二进制常量,由“0”和“1”数字序列组成,前缀为“0b”或“0B”。 This is particularly useful in environments that operate a lot on the bit level (like microcontrollers).这在位级(如微控制器)大量运行的环境中特别有用。

Please check below code snippets to remember and understand even better this solution where we move half by half:请检查下面的代码片段,以记住并更好地理解我们将一半移动的解决方案:

unsigned char reverse(unsigned char b) {
   b = (b & 0b11110000) >> 4 | (b & 0b00001111) << 4;
   b = (b & 0b11001100) >> 2 | (b & 0b00110011) << 2;
   b = (b & 0b10101010) >> 1 | (b & 0b01010101) << 1;
   return b;
}

NB: The >> 4 is because there are 8 bits in 1 byte, which is an unsigned char so we want to take the other half, and so on.注意: >> 4是因为 1 字节中有 8 位,这是一个无符号字符,所以我们要取另一半,依此类推。

We could easily apply this solution to 4 bytes with only two additional lines and following the same logic.我们可以轻松地将此解决方案应用于 4 个字节,只需添加两行并遵循相同的逻辑。 Since both mask complement each other we can even use ~ in order to switch bits and saving some ink:由于两个掩码相互补充,我们甚至可以使用 ~ 来切换位并节省一些墨水:

uint32_t reverse_integer_bits(uint32_t b) {
   uint32_t mask = 0b11111111111111110000000000000000;
   b = (b & mask) >> 16 | (b & ~mask) << 16;
   mask = 0b11111111000000001111111100000000;
   b = (b & mask) >> 8 | (b & ~mask) << 8;
   mask = 0b11110000111100001111000011110000;
   b = (b & mask) >> 4 | (b & ~mask) << 4;
   mask = 0b11001100110011001100110011001100;
   b = (b & mask) >> 2 | (b & ~mask) << 2;
   mask = 0b10101010101010101010101010101010;
   b = (b & mask) >> 1 | (b & ~mask) << 1;
   return b;
}

[C++ Only] Reverse Any Unsigned (Template) [仅限 C++] 反转任何无符号(模板)

The above logic can be summarized with a loop that would work on any type of unsigned:上面的逻辑可以用一个循环来总结,该循环适用于任何类型的无符号:

template <class T>
T reverse_bits(T n) {
    short bits = sizeof(n) * 8; 
    T mask = ~T(0); // equivalent to uint32_t mask = 0b11111111111111111111111111111111;
    
    while (bits >>= 1) {
        mask ^= mask << (bits); // will convert mask to 0b00000000000000001111111111111111;
        n = (n & ~mask) >> bits | (n & mask) << bits; // divide and conquer
    }

    return n;
}

C++ 17 only仅限 C++ 17

You may use a table that store the reverse value of each byte with (i * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff , initialized through a lambda (you will need to compile it with g++ -std=c++1z since it only works since C++17), and then return the value in the table will give you the accordingly reversed bit:您可以使用一个表来存储每个字节反向值(i * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff ,通过 lambda 初始化(您需要使用g++ -std=c++1z编译它,因为它只在 C 之后工作++17),然后返回表中的值会给你相应的反转位:

#include <cstdint>
#include <array>

uint8_t reverse_bits(uint8_t n) {
        static constexpr array<uint8_t, 256> table{[]() constexpr{
                constexpr size_t SIZE = 256;
                array<uint8_t, SIZE> result{};

                for (size_t i = 0; i < SIZE; ++i)
                    result[i] = (i * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff;
                return result;
        }()};

    return table[n];
}

main.cpp主程序

Try it yourself with inclusion of above function:自己尝试包含上述功能:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

template <class T>
void print_binary(T n)
{   T mask = 1ULL << ((sizeof(n) * 8) - 1);  // will set the most significant bit
    for(; mask != 0; mask >>= 1) putchar('0' | !!(n & mask));
    putchar('\n');
}

int main() {
    uint32_t n = 12;
    print_binary(n);
    n = reverse_bits(n); 
    print_binary(n);
    unsigned char c = 'a';
    print_binary(c);
    c = reverse_bits(c);
    print_binary(c);
    uint16_t s = 12;
    print_binary(s);
    s = reverse_bits(s);
    print_binary(s);
    uint64_t l = 12;
    print_binary(l);
    l = reverse_bits(l);
    print_binary(l);
    return 0;
}

Reverse with asm volatile与 asm volatile 反转

Last but not least, if simplest means fewer lines, why not give a try to inline assembly?最后但并非最不重要的一点,如果最简单意味着更少的行,为什么不尝试内联汇编?

You can test below code snippet by adding -masm=intel when compiling:您可以通过在编译时添加-masm=intel来测试以下代码片段:

unsigned char reverse_bits(unsigned char c) {
    __asm__ __volatile__ (R"(
        mov cx, 8       
    daloop:                   
        ror di          
        adc ax, ax      
        dec cx          
        jnz short daloop  
    ;)");
}

Explanations line by line:逐行解释:

        mov cx, 8       ; we will reverse the 8 bits contained in one byte
    daloop:             ; while loop
        shr di          ; Shift Register `di` (containing value of the first argument of callee function) to the Right
        rcl ax          ; Rotate Carry Left: rotate ax left and add the carry from shr di, the carry is equal to 1 if one bit was "lost" from previous operation 
        dec cl          ; Decrement cx
        jnz short daloop; Jump if cx register is Not equal to Zero, else end loop and return value contained in ax register

The simplest way is probably to iterate over the bit positions in a loop:最简单的方法可能是在循环中迭代位位置:

unsigned char reverse(unsigned char c) {
   int shift;
   unsigned char result = 0;
   for (shift = 0; shift < CHAR_BIT; shift++) {
      if (c & (0x01 << shift))
         result |= (0x80 >> shift);
   }
   return result;
}

For the very limited case of constant, 8-bit input, this method costs no memory or CPU at run-time:对于常量 8 位输入的非常有限的情况,此方法在运行时不消耗内存或 CPU:

#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))

I used this for ARINC-429 where the bit order (endianness) of the label is opposite the rest of the word.我将它用于 ARINC-429,其中标签的位顺序(字节序)与单词的其余部分相反。 The label is often a constant, and conventionally in octal.标签通常是一个常数,通常是八进制。

Here's how I used it to define a constant, because the spec defines this label as big-endian 205 octal.这是我如何使用它来定义一个常量,因为规范将这个标签定义为 big-endian 205 八进制。

#define LABEL_HF_COMM MSB2LSB(0205)

More examples:更多例子:

assert(0b00000000 == MSB2LSB(0b00000000));
assert(0b10000000 == MSB2LSB(0b00000001));
assert(0b11000000 == MSB2LSB(0b00000011));
assert(0b11100000 == MSB2LSB(0b00000111));
assert(0b11110000 == MSB2LSB(0b00001111));
assert(0b11111000 == MSB2LSB(0b00011111));
assert(0b11111100 == MSB2LSB(0b00111111));
assert(0b11111110 == MSB2LSB(0b01111111));
assert(0b11111111 == MSB2LSB(0b11111111));
assert(0b10101010 == MSB2LSB(0b01010101));

You may be interested in std::vector<bool> (that is bit-packed) and std::bitset您可能对std::vector<bool> (即位打包)和std::bitset感兴趣

It should be the simplest as requested.它应该是最简单的要求。

#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;
}

Other options may be faster.其他选项可能更快。

EDIT: I owe you a solution using std::vector<bool>编辑:我欠你一个使用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;
}

The second example requires c++0x extension (to initialize the array with {...} ).第二个示例需要 c++0x 扩展(用{...}初始化数组)。 The advantage of using a bitset or a std::vector<bool> (or a boost::dynamic_bitset ) is that you are not limited to bytes or words but can reverse an arbitrary number of bits.使用bitsetstd::vector<bool> (或boost::dynamic_bitset )的优点是您不仅限于字节或字,还可以反转任意数量的位。

HTH HTH

Can this be fast solution?这可以是快速解决方案吗?

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);

Gets rid of the hustle of using a for loop!摆脱使用 for 循环的麻烦! but experts please tell me if this is efficient and faster?但请专家告诉我这是否有效且更快?

Table lookup or查表或

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;
}

edit编辑

Look here for other solutions that might work better for you 在此处查看可能更适合您的其他解决方案

a slower but simpler implementation:一个更慢但更简单的实现:

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;
}

Before implementing any algorithmic solution, check the assembly language for whatever CPU architecture you are using.在实施任何算法解决方案之前,请检查您使用的任何 CPU 架构的汇编语言。 Your architecture may include instructions which handle bitwise manipulations like this (and what could be simpler than a single assembly instruction?).您的架构可能包含处理这样的按位操作的指令(还有什么比单个汇编指令更简单?)。

If such an instruction is not available, then I would suggest going with the lookup table route.如果这样的指令不可用,那么我建议使用查找表路由。 You can write a script/program to generate the table for you, and the lookup operations would be faster than any of the bit-reversing algorithms here (at the cost of having to store the lookup table somewhere).您可以编写一个脚本/程序来为您生成表,并且查找操作将比此处的任何位反转算法都快(代价是必须将查找表存储在某处)。

This simple function uses a mask to test each bit in the input byte and transfer it into a shifting output:这个简单的函数使用掩码来测试输入字节中的每一位并将其传输到移位输出中:

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;
}

Assuming that your compiler allows unsigned long long :假设您的编译器允许unsigned long long

unsigned char reverse(unsigned char b) {
  return (b * 0x0202020202ULL & 0x010884422010ULL) % 1023;
}

Discovered here 在这里发现

This one is based on the one BobStein-VisiBone provided这个是基于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 ) 

I really like this one a lot because the compiler automatically handle the work for you, thus require no further resources.我真的很喜欢这个,因为编译器会自动为你处理工作,因此不需要更多的资源。

this can also be extended to 16-Bits...这也可以扩展到 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 ) 

I know that this question is dated but I still think that the topic is relevant for some purposes, and here is a version that works very well and is readable.我知道这个问题已经过时了,但我仍然认为该主题与某些目的相关,这是一个运行良好且可读的版本。 I can not say that it is the fastest or the most efficient, but it ought to be one of the cleanest.我不能说它是最快或最有效的,但它应该是最干净的之一。 I have also included a helper function for easily displaying the bit patterns.我还包含了一个辅助函数,用于轻松显示位模式。 This function uses some of the standard library functions instead of writing your own bit manipulator.此函数使用一些标准库函数,而不是编写您自己的位操纵器。

#include <algorithm>
#include <bitset>
#include <exception>
#include <iostream>
#include <limits>
#include <string>

// helper lambda function template
template<typename T>
auto getBits = [](T value) {
    return std::bitset<sizeof(T) * CHAR_BIT>{value};
};

// Function template to flip the bits
// This will work on integral types such as int, unsigned int,
// std::uint8_t, 16_t etc. I did not test this with floating
// point types. I chose to use the `bitset` here to convert
// from T to string as I find it easier to use than some of the
// string to type or type to string conversion functions,
// especially when the bitset has a function to return a string. 
template<typename T>
T reverseBits(T& value) {
    static constexpr std::uint16_t bit_count = sizeof(T) * CHAR_BIT;

    // Do not use the helper function in this function!
    auto bits = std::bitset<bit_count>{value};
    auto str = bits.to_string();
    std::reverse(str.begin(), str.end());
    bits = std::bitset<bit_count>(str);
    return static_cast<T>( bits.to_ullong() );
}

// main program
int main() {
    try {
        std::uint8_t value = 0xE0; // 1110 0000;
        std::cout << +value << '\n'; // don't forget to promote unsigned char
        // Here is where I use the helper function to display the bit pattern
        auto bits = getBits<std::uint8_t>(value);
        std::cout << bits.to_string() << '\n';

        value = reverseBits(value);
        std::cout << +value << '\n'; // + for integer promotion

        // using helper function again...
        bits = getBits<std::uint8_t>(value);
        std::cout << bits.to_string() << '\n';

    } catch(const std::exception& e) {  
        std::cerr << e.what();
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

And it gives the following output.它给出了以下输出。

224
11100000
7
00000111

If you using small microcontroller and need high speed solution with small footprint, this could be solutions.如果您使用小型微控制器并需要占用空间小的高速解决方案,这可能是解决方案。 It is possible to use it for C project, but you need to add this file as assembler file *.asm, to your C project.可以将它用于 C 项目,但您需要将此文件作为汇编文件 *.asm 添加到您的 C 项目中。 Instructions: In C project add this declaration:说明:在 C 项目中添加此声明:

extern uint8_t byte_mirror(uint8_t);

Call this function from C从 C 调用这个函数

byteOutput= byte_mirror(byteInput);

This is the code, it is only suitable for 8051 core.这是代码,它只适用于 8051 内核。 In the CPU register r0 is data from byteInput .在 CPU 寄存器r0 中是来自byteInput 的数据。 Code rotate right r0 cross carry and then rotate carry left to r1 .代码向右旋转r0交叉进位,然后向左旋转进位到r1 Repeat this procedure 8 times, for every bit.对每一位重复此过程 8 次。 Then the register r1 is returned to c function as byteOutput.然后寄存器 r1 作为 byteOutput 返回给 c 函数。 In 8051 core is only posibble to rotate acumulator a .在 8051 内核中,只能旋转累加器a

NAME     BYTE_MIRROR
RSEG     RCODE
PUBLIC   byte_mirror              //8051 core        

byte_mirror
    mov r3,#8;
loop:   
    mov a,r0;
    rrc a;
    mov r0,a;    
    mov a,r1;
    rlc a;   
    mov r1,a;
    djnz r3,loop
    mov r0,a
    ret

PROS: It is small footprint, it is high speed CONS: It is not reusable code, it is only for 8051优点:占用空间小,速度高缺点:不可重用代码,仅适用于 8051

011101101->carry 011101101->携带

101101110<-carry 101101110<-携带

It is simple and fast:它简单快捷:

unsigned char reverse(unsigned char rv)无符号字符反向(无符号字符 rv)
{ {
unsigned char tmp=0;无符号字符 tmp=0;
if( rv&0x01 ) tmp = 0x80;如果(rv&0x01)tmp = 0x80;
if( rv&0x02 ) tmp |= 0x40; if( rv&0x02 ) tmp |= 0x40;
if( rv&0x04 ) tmp |= 0x20;如果( rv&0x04 ) tmp |= 0x20;
if( rv&0x08 ) tmp |= 0x10;如果( rv&0x08 ) tmp |= 0x10;
if( rv&0x10 ) tmp |= 0x08; if( rv&0x10 ) tmp |= 0x08;
if( rv&0x20 ) tmp |= 0x04; if( rv&0x20 ) tmp |= 0x04;
if( rv&0x40 ) tmp |= 0x02; if( rv&0x40 ) tmp |= 0x02;
if( rv&0x80 ) tmp |= 0x01; if( rv&0x80 ) tmp |= 0x01;
return tmp;返回 tmp;
} }

This is a similar method to sth's excellent answer, but with optimizations, support for up to 64-bit integers, and other small improvements.这是与 sth 的优秀答案类似的方法,但进行了优化,最多支持 64 位整数,以及其他小的改进。

I utilize a C++ template function reverse_bits() to let the compiler optimize for various word sizes of integers which might be passed to the function.我使用 C++ 模板 function reverse_bits()让编译器针对可能传递给 function 的整数的各种字长进行优化。 The function should work correctly with any word size that is a multiple of 8 bits, up to a maximum of 64 bits. function 应该在任何字长为 8 位的倍数(最多 64 位)的情况下正常工作。 If your compiler supports words longer than 64 bits, the method is straightforward to extend.如果您的编译器支持超过 64 位的字,则该方法很容易扩展。

This a complete, ready-to-compile example with the requisite headers.这是一个完整的、可立即编译的示例,带有必要的头文件。 There is a convenient template function to_binary_str() for creating a std::string representation of binary numbers, along with a few calls with various word sizes to demonstrate everything.有一个方便的模板 function to_binary_str()用于创建二进制数的 std::string 表示,以及一些具有各种字长的调用来演示所有内容。

If you remove the comments and blank lines, the function is quite compact and visually pleasing.如果去掉注释和空行,function 相当紧凑且视觉上令人愉悦。

You can try out it on labstack here .你可以在这里的 labstack 上试用它。

// this is the only header used by the reverse_bits() function
#include <type_traits>

// these headers are only used by demonstration code
#include <string>
#include <iostream>
#include <cstdint>


template<typename T>
T reverse_bits( T n ) {
    // we force the passed-in type to its unsigned equivalent, because C++ may
    // perform arithmetic right shift instead of logical right shift, depending
    // on the compiler implementation.
    typedef typename std::make_unsigned<T>::type unsigned_T;
    unsigned_T v = (unsigned_T)n;

    // swap every bit with its neighbor
    v = ((v & 0xAAAAAAAAAAAAAAAA) >> 1)  | ((v & 0x5555555555555555) << 1);

    // swap every pair of bits
    v = ((v & 0xCCCCCCCCCCCCCCCC) >> 2)  | ((v & 0x3333333333333333) << 2);

    // swap every nybble
    v = ((v & 0xF0F0F0F0F0F0F0F0) >> 4)  | ((v & 0x0F0F0F0F0F0F0F0F) << 4);
    // bail out if we've covered the word size already
    if( sizeof(T) == 1 ) return v;

    // swap every byte
    v = ((v & 0xFF00FF00FF00FF00) >> 8)  | ((v & 0x00FF00FF00FF00FF) << 8);
    if( sizeof(T) == 2 ) return v;

    // etc...
    v = ((v & 0xFFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF) << 16);
    if( sizeof(T) <= 4 ) return v;

    v = ((v & 0xFFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF) << 32);

    // explictly cast back to the original type just to be pedantic
    return (T)v;
}


template<typename T>
std::string to_binary_str( T n ) {
    const unsigned int bit_count = sizeof(T)*8;
    char s[bit_count+1];
    typedef typename std::make_unsigned<T>::type unsigned_T;
    unsigned_T v = (unsigned_T)n;
    for( int i = bit_count - 1; i >= 0; --i ) {
        if( v & 1 )
            s[i] = '1';
        else
            s[i] = '0';

        v >>= 1;
    }
    s[bit_count] = 0;  // string null terminator
    return s;
}


int main() {
    {
        char x = 0xBA;
        std::cout << to_binary_str( x ) << std::endl;

        char y = reverse_bits( x );
        std::cout << to_binary_str( y ) << std::endl;
    }
    {
        short x = 0xAB94;
        std::cout << to_binary_str( x ) << std::endl;

        short y = reverse_bits( x );
        std::cout << to_binary_str( y ) << std::endl;
    }
    {
        uint64_t x = 0xFEDCBA9876543210;
        std::cout << to_binary_str( x ) << std::endl;

        uint64_t y = reverse_bits( x );
        std::cout << to_binary_str( y ) << std::endl;
    }
    return 0;
}

With the help of various online resources, i jotted these for myself (not sure if they're 100% accurate):在各种在线资源的帮助下,我自己记下了这些(不确定它们是否 100% 准确):

#                 octal       hex

# bit-orig    : 01234567    01234567:89ABCDEF
# bit-invert  : 76543210    FEDCBA98:76543210
#
# clz         : 32110000    43221111:00000000
# clo/ffs     : 00001123    00000000:11112234

bit-reverse: [ 0 4 2 6 1 5 3 7 ] [ 0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F ]位反转: [ 0 4 2 6 1 5 3 7 ] [ 0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F ]

# cto         : 01020103    01020103:01020104
# ctz         : 30102010    40102010:30102010

but this is mostly only convenient if your input is already either hex or octal.但这仅在您的输入已经是十六进制或八进制时才方便。

In both formats (8 or 16), you'll notice that after the bit-reflections, all the even number indices are all on the first half.在这两种格式(8 或 16)中,您会注意到在位反射之后,所有偶数索引都在前半部分。 I've also highlighted the same 0-7 on the hex side to help with the visualization of it.我还在十六进制侧突出显示了相同的 0-7,以帮助对其进行可视化。

in fact, one doesn't even have to do a double substring.事实上,甚至不必做一个双 substring。 The lookup string can be either used as seeking the letter needed, or simply use it as an index lookup.查找字符串既可以用作查找所需的字母,也可以简单地将其用作索引查找。 this is how i reflect the CRC32 polynomial myself:这就是我自己反映 CRC32 多项式的方式:

(z is the input polynomial (or just any hex string)

xn = 0 ^ (x = length(z));          # initialize to numeric 0,
                                   # foo^bar in awk means 
                                   # foo-to-bar-th-power. 
                                   # same as foo**bar in other langs

 y = substr(_REF_bitREV_hex, 2);   # by pre-trimming the lookup str,
                                   # it allows skipping the + 1 at            
                                   # every cycle of the loop
 do { 
     xn *= 16
     xn += index(y, substr(z,x,1)) # keep in mind that this is awk syntax, 
                                   # where strings start at index-1, not zero.
 } while ( 1 < x—- );

One advantage of using a hex- or octal- based approach is that it allows for inputs of any length, enabling arbitrary precision operation without having to use a proper BigInteger or BigFloat library.使用基于十六进制或八进制的方法的一个优点是它允许任何长度的输入,无需使用适当的 BigInteger 或 BigFloat 库即可实现任意精度操作。 For that, you'll have to substring out the new digit/letter and do string concats instead of simply adding each time.为此,您必须将 substring 取出新的数字/字母并进行字符串连接,而不是每次都简单地添加。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i;
    unsigned char rev = 0x70 ; // 0b01110000
    unsigned char tmp = 0;

    for(i=0;i<8;i++)
    {
    tmp |= ( ((rev & (1<<i))?1:0) << (7-i));
    }
    rev = tmp;

    printf("%x", rev);       //0b00001110 binary value of given number
    return 0;
}
  xor ax,ax
  xor bx,bx
  mov cx,8
  mov al,original_byte!
cycle:   shr al,1
  jnc not_inc
  inc bl
not_inc: test cx,cx
  jz,end_cycle
  shl bl,1
  loop cycle
end_cycle:

reversed byte will be at bl register反转字节将在bl寄存器

typedef struct
{
    uint8_t b0:1;
    uint8_t b1:1;
    uint8_t b2:1;
    uint8_t b3:1;
    uint8_t b4:1;
    uint8_t b5:1;
    uint8_t b6:1;
    uint8_t b7:1;
} bits_t;

uint8_t reverse_bits(uint8_t src)
{
    uint8_t dst = 0x0;
    bits_t *src_bits = (bits_t *)&src;
    bits_t *dst_bits = (bits_t *)&dst;

    dst_bits->b0 = src_bits->b7;
    dst_bits->b1 = src_bits->b6;
    dst_bits->b2 = src_bits->b5;
    dst_bits->b3 = src_bits->b4;
    dst_bits->b4 = src_bits->b3;
    dst_bits->b5 = src_bits->b2;
    dst_bits->b6 = src_bits->b1;
    dst_bits->b7 = src_bits->b0;

    return dst;
}

I think this is simple enough我觉得这很简单

uint8_t reverse(uint8_t a)
{
  unsigned w = ((a << 7) & 0x0880) | ((a << 5) & 0x0440) | ((a << 3) & 0x0220) | ((a << 1) & 0x0110);
  return static_cast<uint8_t>(w | (w>>8));
}

or或者

uint8_t reverse(uint8_t a)
{
  unsigned w = ((a & 0x11) << 7) | ((a & 0x22) << 5) | ((a & 0x44) << 3) | ((a & 0x88) << 1);
  return static_cast<uint8_t>(w | (w>>8));
}
unsigned char c ; // the original
unsigned char u = // the reversed
c>>7&0b00000001 |
c<<7&0b10000000 |
c>>5&0b00000010 |
c<<5&0b01000000 |
c>>3&0b00000100 |
c<<3&0b00100000 |
c>>1&0b00001000 |
c<<1&0b00010000 ;

Explanation: exchanged bits as per the arrows below.
01234567
<------>
#<---->#
##<-->##
###<>###
#include <stdio.h>
#include <stdlib.h>

#define BIT0 (0x01)
#define BIT1 (0x02)
#define BIT2 (0x04)
#define BIT3 (0x08)
#define BIT4 (0x10)
#define BIT5 (0x20)
#define BIT6 (0x40)
#define BIT7 (0x80)

#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c\n"

#define BITETOBINARY(byte) \
(byte & BIT7 ? '1' : '0'), \
(byte & BIT6 ? '1' : '0'), \
(byte & BIT5 ? '1' : '0'), \
(byte & BIT4 ? '1' : '0'), \
(byte & BIT3 ? '1' : '0'), \
(byte & BIT2 ? '1' : '0'), \
(byte & BIT1 ? '1' : '0'), \
(byte & BIT0 ? '1' : '0') \

#define BITETOBINARYREVERSE(byte) \
(byte & BIT0 ? '1' : '0'), \
(byte & BIT1 ? '1' : '0'), \
(byte & BIT2 ? '1' : '0'), \
(byte & BIT3 ? '1' : '0'), \
(byte & BIT4 ? '1' : '0'), \
(byte & BIT5 ? '1' : '0'), \
(byte & BIT6 ? '1' : '0'), \
(byte & BIT7 ? '1' : '0') \



int main()
{

    int i,j,c;

    i |= BIT2|BIT7;

    printf("0x%02X\n",i);    

    printf(BYTE_TO_BINARY_PATTERN,BITETOBINARY(i));

    printf("Reverse");

    printf(BYTE_TO_BINARY_PATTERN,BITETOBINARYREVERSE(i));

   return 0;
}

I'll chip in my solution, since i can't find anything like this in the answers so far.我会加入我的解决方案,因为到目前为止我在答案中找不到这样的东西。 It is a bit overengineered maybe, but it generates the lookup table using C++14 std::index_sequence in compile time.它可能有点过度设计,但它在编译时使用 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 https://godbolt.org/z/cSuWhF

Here is a simple and readable solution, portable to all conformant platforms, including those with sizeof(char) == sizeof(int) :这是一个简单易读的解决方案,可移植到所有符合标准的平台,包括那些具有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;
}

This one helped me with 8x8 dot matrix set of arrays.这个帮助我处理了 8x8 点阵数组。

uint8_t mirror_bits(uint8_t var)
{
    uint8_t temp = 0;
    if ((var & 0x01))temp |= 0x80;
    if ((var & 0x02))temp |= 0x40;
    if ((var & 0x04))temp |= 0x20;
    if ((var & 0x08))temp |= 0x10;

    if ((var & 0x10))temp |= 0x08;
    if ((var & 0x20))temp |= 0x04;
    if ((var & 0x40))temp |= 0x02;
    if ((var & 0x80))temp |= 0x01;

    return temp;
}

regarding the bit-reflected lookup table for all 256 bytes, with just a few loops, you can generate it from scratch on the fly very quickly (the mapping from hex to bytes should be trivial):关于所有 256 个字节的位反射查找表,只需几个循环,您就可以非常快速地从头开始生成它(从十六进制到字节的映射应该很简单):

 #  gawk profile,created Tue Jul 26 22:22:18 2022

 #  BEGIN rule(s)
    BEGIN {
 1      print initREF()
    }
 # Functions,listed alphabetically
 1  function initREF(_,__,___,____,_____,______,_______)
    {
 1     ______=(_+=_^=_<_)^++_-(_=\
           __=(+(___=____="."))(_~_))

 1     gsub(___,"&\\&",_)
 1     _____[_<_]
       _____[ +_]

 7     do {
 7         gsub(___,_,__)
 7         ___=___""____
       } while (—______)

 1     gsub("....","=&", __)
 1     _+=_^=_<_;_______=__;

 2     for(______ in _____) { ______*=_*_*_
 4        for(____ in _____) {  ____*=_+_
 8           for(___ in _____) { ___*= +_
16              for(__ in _____) {

16                    gsub("=" (_<______)(_<____) (_~___)__,
                   sprintf("%X", __+___+____+______),_______)
        } } } }

 1      __=_______
 1       _="[^ ]+[ ]"
 1      gsub(".",_,_)

 1      gsub("..","0x&, ",__)
 1      gsub((_)_,  "&\n",__)
 1      sub("[\1-@]+$","",__)
 1            gsub(" ","",__)

 1      return __
    }

| |

0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF

This is the easiest approach to remember to me as a developer:作为开发人员,这是我最容易记住的方法:

unsigned char   reverse_bits(unsigned char octet)
    {
        return  (((octet >> 0) & 1) << 7) | \
                (((octet >> 1) & 1) << 6) | \
                (((octet >> 2) & 1) << 5) | \
                (((octet >> 3) & 1) << 4) | \
                (((octet >> 4) & 1) << 3) | \
                (((octet >> 5) & 1) << 2) | \
                (((octet >> 6) & 1) << 1) | \
                (((octet >> 7) & 1) << 0);
    }
 

If there is one wondering how to get uint16_t or uint32_t bit reversed by using the solution from Rich Schroeppel in the Programming Hacks section如果有人想知道如何使用编程技巧部分中Rich Schroeppel的解决方案来反转uint16_tuint32_t

unsigned char reverse_bits3(unsigned char b)
{
    return (b * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff;
}

It can be done by following divide-and-conquer code on X86/X64 platform (little-endian):它可以通过在 X86/X64 平台(小端)上的以下分而治之代码来完成:

uint16_t reverse_bits3(uint16_t s)
{
    uint8_t &b0 = ((uint8_t*)&s)[0];
    uint8_t &b1 = ((uint8_t*)&s)[1];
    return (((uint16_t)reverse_bits3(b0))<<8) + reverse_bits3(b1);
}

uint32_t reverse_bits3(uint32_t u)
{
    uint16_t &s0 = ((uint16_t*)&u)[0];
    uint16_t &s1 = ((uint16_t*)&u)[1];
    return (((uint16_t)reverse_bits3(s0))<<16) + reverse_bits3(s1);
}
#define BITS_SIZE 8

int
reverseBits ( int a )
{
  int rev = 0;
  int i;

  /* scans each bit of the input number*/
  for ( i = 0; i < BITS_SIZE - 1; i++ )
  {
    /* checks if the bit is 1 */
    if ( a & ( 1 << i ) )
    {
      /* shifts the bit 1, starting from the MSB to LSB
       * to build the reverse number 
      */
      rev |= 1 << ( BITS_SIZE - 1 ) - i;
    }
  }

  return rev;
}

How about this one... 这个怎么样...

int value = 0xFACE;

value = ((0xFF & value << 8) | (val >> 8);

This is an old question, but nobody seems to have shown the clear easy way (the closest was edW). 这是一个老问题,但似乎没有人表现出明确的简单方法(最接近edW)。 I used C# to test this, but there's nothing in this example that couldn't be done easily in C. 我使用C#来测试这个,但是在这个例子中没有任何东西在C中无法轻易完成。

void PrintBinary(string prompt, int num, int pad = 8)
{
    Debug.WriteLine($"{prompt}: {Convert.ToString(num, 2).PadLeft(pad, '0')}");
}

int ReverseBits(int num)
{
    int result = 0;
    int saveBits = num;
    for (int i = 1; i <= 8; i++)
    {
        // Move the result one bit to the left
        result = result << 1;

        //PrintBinary("saveBits", saveBits);

        // Extract the right-most bit
        var nextBit = saveBits & 1;

        //PrintBinary("nextBit", nextBit, 1);

        // Add our extracted bit to the result
        result = result | nextBit;

        //PrintBinary("result", result);

        // We're done with that bit, rotate it off the right
        saveBits = saveBits >> 1;

        //Debug.WriteLine("");
    }

    return result;
}

void PrintTest(int nextNumber)
{
    var result = ReverseBits(nextNumber);

    Debug.WriteLine("---------------------------------------");
    PrintBinary("Original", nextNumber);
    PrintBinary("Reverse", result);
}

void Main()
{
    // Calculate the reverse for each number between 1 and 255
    for (int x = 250; x < 256; x++)
        PrintTest(x);
}

如何用0xFF对字节进行异或。

unsigned char reverse(unsigned char b) { b ^= 0xFF; return b; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 获取字节中4个最低有效位(C ++)的最快方法是什么? - What is the fastest way to get the 4 least significant bits in a byte (C++)? 在 C++ 中测试一个数字是否是 2 的幂的最简单方法是什么? - What's the simplest way to test whether a number is a power of 2 in C++? 在c ++中,最快的反向排序方式是什么? - In c++, what is the fastest way to sort in reverse order? 在C / C ++中向指针添加1个字节的正确方法是什么? - What's the correct way to add 1 byte to a pointer in C/C++? C ++:在Windows上使用C ++读写BMP文件的最简单方法是什么? - C++: What's the simplest way to read and write BMP files using C++ on Windows? 在C ++中定义类型安全的“字节”(如8位)类型的最现代和惯用的方法是什么? - What is the most modern and idiomatic way to define a type safe “byte” ( as in 8 bits ) type in C++? 有没有一种方法可以反转C ++中数组的顺序? - Is there a way to reverse the order of an array in C++? &#39;/usr/include/c++/4.4/bits/&#39;中位的含义是什么? - What's the meaning of bits in '/usr/include/c++/4.4/bits/' 在 C/C++ 中编写计时器的最简单方法是什么? - What is the simplest way to write a timer in C/C++? 在 C/C++ 中获取和设置字节中的位 - Getting and setting bits in a byte in C/C++
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM