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

时间:2010-04-08 19:32:08

标签: c++ c bit-manipulation

虽然有多种方法可以在一个字节中反转位顺序,但我很好奇开发人员实现的“最简单”。通过颠倒我的意思是:

1110 -> 0111
0010 -> 0100

这与this PHP问题类似,但不重复。

这与this C问题类似,但不重复。这个问题要求开发人员实施最简单的方法。 “最佳算法”关注内存和CPU性能。

35 个答案:

答案 0 :(得分:199)

这应该有效:

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

首先,左四位与右四位交换。然后交换所有相邻对,然后交换所有相邻的单个位。这会导致相反的顺序。

答案 1 :(得分:112)

我认为查找表必须是最简单的方法之一。但是,您不需要完整的查找表。

//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]

这在视觉上进行编码和验证相当简单 最终,这甚至可能比完整的表更快。位数便宜,表格很容易适合缓存行。

答案 2 :(得分:90)

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

答案 3 :(得分:43)

有关许多解决方案,请参阅bit twiddling hacks。从那里进行复制显然很容易实现。 =)

例如(在32位CPU上):

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

如果通过“简单实施”意味着可以在考试或求职面试中没有参考的情况下完成,那么最安全的赌注可能是以相反的顺序将比特一个接一个地复制到另一个变量中(已经显示)在其他答案)。

答案 4 :(得分:36)

由于没有人发布完整的表查找解决方案,这是我的:

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

答案 5 :(得分:25)

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

修改

使用可选的bitcount

将其转换为模板

答案 6 :(得分:15)

两行:

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

或者如果您遇到“0b1”部分的问题:

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

“original”是您要反转的字节。 “反转”是结果,初始化为0。

答案 7 :(得分:12)

虽然可能不便携,但我会使用汇编语言 许多汇编语言都有指令将位旋转到进位标志并将进位标志旋转到字(或字节)中。

算法是:

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

高级语言代码要复杂得多,因为C和C ++不支持旋转来携带和旋转。进位标志必须建模。

编辑:汇编语言,例如

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

答案 8 :(得分:10)

最简单的方式可能是迭代循环中的位位置:

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

答案 9 :(得分:9)

根据您所说的“最简单的方式”,有许多种方法可以反转位。


旋转反转

可能最合乎逻辑的是,在对第一位(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)由于取消签名者char的长度为1个字节,等于8位,这意味着我们将扫描每一位while (byte_len--)

2)我们首先用(b & 1)检查b是否在最右边。 如果是这样,我们用|在r上设置位1,然后将其向左移动1位。 用(r << 1)

将r乘以2

3)然后我们用b >>=1将未签名的char b除以2以擦除 位于变量b最右端的位。 提醒一下,b >> = 1;等于b / = 2;


单行倒退

此解决方案归因于Rich Schroeppel in the Programming Hacks section

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

1)乘法运算(b * 0x0202020202ULL)创建8位字节模式的五个单独副本,以扇出为64位值。

2)AND操作(&0x010884422010ULL)选择 相对于每个10位位组正确(反转)的位置。

3)乘法和AND操作一起复制原始位 字节,因此它们每个仅出现在10位集中的一组中。 与原始字节相反的位与它们的位置重合 任何10位集中的相对位置。

4)最后一步(%0x3ff),其中模数除以2 ^ 10-1 具有将每组10位合并在一起的效果 (从0-9、10-19、20-29等位置)从64位值开始。 它们不重叠,因此模数下的加法步骤 除的行为类似于OR操作。


分而治之的解决方案

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

这是最受支持的答案,尽管有一些解释,但我认为对于大多数人来说,很难直观地看到0xF0、0xCC,0xAA,0x0F,0x33和0x55的含义。

它没有利用'0b'这个GCC extension的优势,并且自2014年12月发布的C ++ 14标准以来就包含在其中,因此此答案的日期为2010年4月之后

整数常量可以写为二进制常量,它由数字“ 0”和“ 1”组成,并以“ 0b”或“ 0B”为前缀。这对于在比特级上需要大量操作的环境(例如微控制器)特别有用。

请检查下面的代码片段,以记住并更好地理解我们逐步移动的解决方案:

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

注意:>> 4是因为1字节中有8位,这是一个无符号字符,所以我们要取另一半,依此类推。

我们可以轻松地将此解决方案应用到4个字节,而只需增加两行并遵循相同的逻辑。由于两个掩码互为补充,我们甚至可以使用〜来切换位并节省一些墨水:

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 ++]反转所有未签名的(模板)

上面的逻辑可以用一个可以在任何类型的无符号上运行的循环来概括:

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

包括上述功能,请自己尝试:

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

使用asm volatile反转

最后但并非最不重要的一点,如果最简单意味着更少的行,为什么不尝试内联汇编呢?

您可以在编译时通过添加-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  
    ;)");
}

逐行解释:

        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

答案 10 :(得分:7)

对于常量,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))

我将它用于ARINC-429,其中标签的位顺序(字节顺序)与单词的其余部分相反。标签通常是常量,通常是八进制的。例如:

#define LABEL_HF_COMM MSB2LSB(0205)

答案 11 :(得分:6)

您可能对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扩展(用{...}初始化数组)。使用bitsetstd::vector<bool>(或boost::dynamic_bitset)的优点是您不限于字节或字,但可以反转任意数量的位。

HTH

答案 12 :(得分:3)

表查找或

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

修改

查看here以了解可能更适合您的其他解决方案

答案 13 :(得分:2)

更慢但更简单的实现:

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

答案 14 :(得分:2)

在实施任何算法解决方案之前,请检查汇编语言以了解您正在使用的任何CPU架构。您的体系结构可能包含处理这种按位操作的指令(以及可能比单个汇编指令更简单的操作?)。

如果这样的指令不可用,那么我建议使用查找表路由。您可以编写脚本/程序来为您生成表,并且查找操作将比此处的任何位反转算法更快(代价是必须在某处存储查找表)。

答案 15 :(得分:2)

这可以快速解决吗?

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循环的喧嚣!但专家请告诉我这是否有效且更快?

答案 16 :(得分:2)

这个简单的函数使用掩码测试输入字节中的每个位并将其传输到移位输出:

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

答案 17 :(得分:1)

如果您使用小型微控制器并且需要占用空间小的高速解决方案,那么这可能是解决方案。可以将其用于C项目,但是您需要将此文件作为汇编文件* .asm添加到C项目。 说明: 在C项目中添加以下声明:

extern uint8_t byte_mirror(uint8_t);

从C调用此函数

byteOutput= byte_mirror(byteInput);

这是代码,它仅适用于8051内核。在CPU寄存器 r0 中是来自 byteInput 的数据。代码向右旋转 r0 交叉进位,然后向左旋转进位 r1 。每位重复此过程8次。然后,将寄存器r1作为字节输出返回给c函数。在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:占地面积小,速度快 缺点:它不是可重用的代码,仅适用于8051

011101101->携带

101101110 <-carry

答案 18 :(得分:1)

这个是基于提供的BobStein-VisiBone

!/0

我非常喜欢这个,因为编译器会自动为您处理工作,因此无需其他资源。

这也可以扩展到16位......

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

答案 19 :(得分:0)

简单快捷:

<块引用>

无符号字符反转(无符号字符RV)
{
无符号字符 tmp=0;
if(rv&0x01)tmp = 0x80;
如果(rv&0x02)tmp |= 0x40;
如果(rv&0x04)tmp |= 0x20;
如果(rv&0x08)tmp |= 0x10;
如果(rv&0x10)tmp |= 0x08;
如果( rv&0x20 ) tmp |= 0x04;
如果(rv&0x40)tmp |= 0x02;
如果(rv&0x80)tmp |= 0x01;
return tmp;
}

答案 20 :(得分:0)

这帮助我处理了8x8点阵阵列。

treeMember x (Node a l r) |x `elem` [a]  = True
                          |otherwise = treeMember x l || treeMember x r

答案 21 :(得分:0)

假设您的编译器允许 unsigned long long

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

Discovered here

答案 22 :(得分:0)

我知道这个问题已经过时,但是我仍然认为该主题对于某些目的而言是相关的,这是一个工作得很好并且易于阅读的版本。我不能说这是最快或最有效的,但它应该是最干净的一种。我还提供了一个帮助程序功能,可轻松显示位模式。此函数使用一些标准库函数,而不是编写自己的位操纵器。

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

它给出以下输出。

224
11100000
7
00000111

答案 23 :(得分:0)

这是一个简单易读的解决方案,可移植到所有兼容平台,包括使用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;
}

答案 24 :(得分:0)

我会努力解决,因为到目前为止我在答案中都找不到这样的东西。也许有些工程过度,但是它在编译时使用C ++ 14 CSharpSyntaxTree.ParseText生成了查找表。

ParsedSyntaxTree

https://godbolt.org/z/cSuWhF

答案 25 :(得分:0)

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

答案 26 :(得分:0)

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

答案 27 :(得分:0)

我认为这很简单

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

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

答案 28 :(得分:0)

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

答案 29 :(得分:0)

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

答案 30 :(得分:-1)

  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:

反向字节将位于 bl 寄存器

答案 31 :(得分:-1)

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

答案 32 :(得分:-2)

这是一个老问题,但似乎没有人表现出明确的简单方法(最接近edW)。我使用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);
}

答案 33 :(得分:-2)

这个怎么样......

int value = 0xFACE;

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

答案 34 :(得分:-4)

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

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