在C语言中如何仅设置一个字节的特定位而不影响其余位?

24
说我有一个字节,像这样的 1010XXXX,其中 X 的值可以是任何东西。 我想将低四位设置为特定模式,例如 1100,同时不影响高四位。在 C 语言中,我该如何以最快的速度实现这一点?

4个回答

60

一般而言:

value = (value & ~mask) | (newvalue & mask);

mask 是一个特定的值,其中需要改变(而且只有它们)的位被设置为1 - 在您的情况下,它将是0xf。 newvalue 是包含这些位新状态的值 - 其他所有位基本上都被忽略。

对于支持按位运算符的所有类型,都可以使用此方法。


2
请您能否给出一个具体的例子?假设我有:n = 1024。我想将从第3位到第7位(包括第3位和第7位,从最低有效位开始计数)的位改为k = 19。结果应该是:1176。我该如何实现它?谢谢。 - dh16
2
刚刚我自己也不得不解决这个问题,我想出了以下宏来概括这个问题。(不知道为什么代码格式化不起作用,抱歉)#define MASK(L,P) (~(0xffffffff << (L)) << (P)) #define GET_VAL(BF,L,P) (((BF) & MASK(L,P)) >> P) #define SET_VAL(BF,L,P,V) ( (BF) = ((BF) & ~MASK(L,P)) | (((V) << (P)) & MASK(L,P)) ) int main(int argc, char ** argv) { uint32_t bf = 1024; printf("位域之前 : %d , 0x%08x\n", bf, bf); SET_VAL(bf,5,3,19); printf("位域之后 : %d , 0x%08x\n", bf, bf); return 0; } - Micha

20

你可以通过按位与操作将所有这些位设置为0,其中4个位设置为0,所有其他位均设置为1(这是4个位设置为1的补码)。然后,您可以像通常一样按位或入位。

 val &= ~0xf; // Clear lower 4 bits. Note: ~0xf == 0xfffffff0
 val |= lower4Bits & 0xf; // Worth anding with the 4 bits set to 1 to make sure no
                          // other bits are set.

2
为什么 ~0xf 等于 0x0000000f(四个字节),而不是三个字节或五个字节?编译器是否根据要与之进行 AND 操作的 sizeof val 决定了长度为 4? - doc_id
1
@doc_id: 我假设val是一个32位整数。它可能是16位或64位,但不太可能是24位或40位,因为它们不是标准的整数类型... - Goz

3
为了进一步概括所给的答案,这里提供了几个宏(针对32位值;根据不同的位域长度进行调整)。
#include <stdio.h>
#include <stdint.h>

#define MASK(L,P)            (~(0xffffffff << (L)) << (P))

#define GET_VAL(BF,L,P)      (((BF) & MASK(L,P)) >> P)
#define SET_VAL(BF,L,P,V)    ( (BF) = ((BF) & ~MASK(L,P)) | (((V) << (P)) & MASK(L,P)) )

int main(int argc, char ** argv)
{
    uint32_t bf = 1024;

    printf("Bitfield before : %d , 0x%08x\n", bf, bf);

    
    printf("Mask(5,3): %d , 0x%08x\n", MASK(5,3), MASK(5,3));


    SET_VAL(bf,5,3,19);
    printf("Bitfield after : %d , 0x%08x\n", bf, bf);

    return 0;
}

作为一件小事,C语言的位域是完全无用的。它是实现这个要求的完美语法糖,但由于让每个编译器自行实现,因此在任何实际应用中都是无用的。

2
使用按位或运算符|,当你想将字节的位从0变为1时使用。
使用按位与运算符&,当你想将字节的位从1变为0时使用。
示例
#include <stdio.h>

int byte;
int chb;

int main() {
    // Change bit 2 of byte from 0 to 1
    byte = 0b10101010;
    chb = 0b00000100;        // 0 to 1 change byte
    printf("%d\n", byte);    // Display current status of byte

    byte = byte | chb;       // Perform 0 to 1 single bit changing operation
    printf("%d\n", byte);

    // Change bit 2 of byte back from 1 to 0
    chb = 0b11111011;        // 1 to 0 change byte

    byte = byte & chb;       // Perform 1 to 0 single bit changing operation
    printf("%d\n", byte);
}

也许有更好的方法,我不知道。这暂时会对你有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接