在C中交换整数中的位,你能给我解释一下这个函数吗?

在C中交换整数中的位,你能给我解释一下这个函数吗?,c,bit-manipulation,bitwise-operators,swap,bitwise-xor,C,Bit Manipulation,Bitwise Operators,Swap,Bitwise Xor,我想写一个函数,它接收一个无符号字符,在第2位和第4位之间交换,并返回新的数字 我不允许使用if语句 unsigned char SwapBits(unsigned char num) { // preserve only bit 2 unsigned char bit2 = num & 0x04; // preserve only bit 4 unsigned char bit4 = num & 0x10; // mo

我想写一个函数,它接收一个
无符号字符
,在
第2位
第4位
之间交换,并返回新的数字

我不允许使用
if
语句

unsigned char SwapBits(unsigned char num)
{
    // preserve only bit 2
    unsigned char bit2 = num & 0x04;
    
    // preserve only bit 4
    unsigned char bit4 = num & 0x10;
    
    // move bit 2 left to bit 4 position
    unsigned char bit2_moved = bit2 << 2;
    
    // move bit 4 right to bit 2 position
    unsigned char bit4_moved = bit4 >> 2;
    
    // put the two moved bits together into one swapped value
    unsigned char swapped_bits  = bit2_moved | bit4_moved;
    
    // clear bits 2 and 4 from the original value
    unsigned char num_with_swapped_bits_cleared = num & ~0x14;
    
    // put swapped bits back into the original value to complete the swap
    return num_with_swapped_bits_cleared | swapped_bits;
} 
所以我找到了这个函数,在其他函数中,但这是最简单的一个

所有其他函数都涉及异或,老实说,我并不真正理解

unsigned char SwapBits(unsigned char num)
{
    
    unsigned char mask2 = ( num & 0x04 ) << 2;
    
    unsigned char mask4 = ( num & 0x10 ) >> 2;
    
    unsigned char mask  = mask3 | mask5 ;
    
    return ( num & 0xeb ) | mask;


}    
unsigned char SwapBits(unsigned char num)
{
无符号字符mask2=(num&0x04)>2;
无符号字符掩码=mask3 | mask5;
返回(num&0xeb)|掩码;
}    
有人能告诉我这里发生了什么,最重要的是为什么吗? 此处为什么需要AND,为什么需要使用
十六进制地址
? 为什么我应该使用
0xeb
(255)?我知道这是char的范围,但我为什么要这样做呢

总之,, 我知道怎么读密码。我理解这段代码,但我不理解每一行的目的


谢谢。

首先,通常的惯例是从0开始对最低有效位进行编号,然后向上计数。在本例中,您有一个8位的值,因此位从右侧的0到左侧的7

你发布的功能仍然不太正确,但我想我明白你(它)的意图。以下是它正在执行的步骤:

  • 使用遮罩拉出第2位(从右侧第3位)
  • 使用遮罩拉出第4位(从右侧第5位)
  • 将位2向左移动2个位置,使其现在处于位4的原始位置
  • 将第4位向右移动2个位置,使其现在处于第2位的原始位置
  • 将这两个位合并到一个值中,该值现在被第2位和第4位交换
  • 仅从原始值中屏蔽(使用&)位2和4
  • 加入(使用|插入)新交换的位2和4以完成转换
  • 我已经重写了函数,每次显示一个步骤,以帮助使其更清晰。在原始函数或您找到的其他示例中,您将看到许多这些步骤都在同一语句中同时发生

    unsigned char SwapBits(unsigned char num)
    {
        // preserve only bit 2
        unsigned char bit2 = num & 0x04;
        
        // preserve only bit 4
        unsigned char bit4 = num & 0x10;
        
        // move bit 2 left to bit 4 position
        unsigned char bit2_moved = bit2 << 2;
        
        // move bit 4 right to bit 2 position
        unsigned char bit4_moved = bit4 >> 2;
        
        // put the two moved bits together into one swapped value
        unsigned char swapped_bits  = bit2_moved | bit4_moved;
        
        // clear bits 2 and 4 from the original value
        unsigned char num_with_swapped_bits_cleared = num & ~0x14;
        
        // put swapped bits back into the original value to complete the swap
        return num_with_swapped_bits_cleared | swapped_bits;
    } 
    
    unsigned char SwapBits(unsigned char num)
    {
    //只保留第2位
    无符号字符位2=num&0x04;
    //只保留第4位
    无符号字符位4=num&0x10;
    //将位2向左移动到位4位置
    无符号字符比特2_moved=比特2>2;
    //将两个移动的位合并为一个交换值
    无符号字符交换位=位2移动位4移动位;
    //从原始值中清除位2和4
    无符号字符num_,带交换位_cleared=num&~0x14;
    //将交换的位放回原始值以完成交换
    返回已交换位已清除的num_ |已交换位;
    } 
    
    倒数第二步
    num&~0x14
    可能需要一些解释。因为我们想保存除第2位和第4位以外的所有原始位,所以我们只屏蔽(擦除)正在更改的位,而不处理其他所有位。我们要擦除的位位于位置2和4,即掩码0x14中的1。所以我们在0x14上做一个补码(~),把它变成所有的1,除了位2和4中的0。然后,我们将这个值与原始数相加,其效果是将第2位和第4位更改为0,而不考虑其他所有位。这使我们能够将新的交换位作为完成该过程的最后一步。您必须阅读

    unsigned char SwapBits(unsigned char num)
    {
    //假设[num]=46,这意味着表示为0b00101110
    无符号字符mask2=(num&0x04)>2;
    //0b00101110个
    //0b00010000 0x10->表示十进制的16或二进制的0b10000或2^4(幂也是位设置后尾随的0的数目)
    //0b00…..0 mask4=0,未能同时设置所有位
    无符号字符掩码=mask3 | mask5;
    //如果mask3[或]mask5设置为:
    //0b1001 mask3
    //0boo11 mask4
    //0b1011掩模
    return(num&0xeb)| mask;//您现在知道它是如何工作的了;)解决这个问题。PS:括号之间的操作具有优先级
    }    
    
    如果您有兴趣学习位运算符的基础知识,可以查看

    建立信心后,您可以尝试探索更深层次的按位操作,并查看其对运行时的影响;)

    我也推荐阅读,老掉牙的但是好东西

    b=((b*0x80200802ULL)&0x0884422110ULL)*0x0101010101ULL>>32;//反转你的字节!
    

    理解第3位和第5位交换的简单函数: 如果要交换位索引3和位索引5,则必须执行以下操作:

    int n=0b100010
    int mask=0b100000//保留位索引5(从索引0开始)
    int mask2=0b1000//保留位索引3
    n=(n&mask)>>2 |(n&mask2)>2
    //掩码索引5减少2个位置(>>2),并带来位于索引5处的位,由于and操作数,它在n中捕获了该位。
    
    //|(n&mask2)没有地址。十六进制值只是位掩码。在纸上一步一步地计算出来,你会学得更好。@Barmar为什么我们必须
    >2
    这个
    >2
    看起来很明显。位3和位5相隔两位。你在这里交换他们的位置。然而,
    0x03
    0x05
    确实很奇怪。你确定他们是对的吗?它们不应该是
    0b10000
    (屏蔽第5位)和
    0b100
    (屏蔽第3位)吗?顺便说一句:0xeb不是255,它是235=0b11101011。啊,你请人解释这个函数是如何工作的,但它不工作(你在将原始函数调整到新用途时出错)。也许你应该发布你找到的原始工作代码,并得到解释,然后应用你想要的