如何在 C 中仅设置字节的某些位而不影响其余部分?

问题描述 投票:0回答:4

假设我有一个像 1010XXXX 这样的字节,其中 X 值可以是任何值。我想将低四位设置为特定模式,例如 1100,同时保持高四位不受影响。我怎样才能用 C 语言最快地做到这一点?

c byte bitmask
4个回答
59
投票

总体来说:

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

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

这适用于支持按位运算符的所有类型。


20
投票

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

 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
投票

为了进一步概括给出的答案,这里有几个宏(针对 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 位域完全没用,这很荒谬。它是满足此要求的完美语法糖,但由于将其留给每个编译器按照其认为合适的方式实现,因此它对于任何实际用途都是无用的。


1
投票

当您想要将字节的位从 0 更改为 1 时,请使用 按位 OR 运算符

|

当您想要将字节的位从 1 更改为 0 时,请使用 按位 AND 运算符

&

示例

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

也许还有更好的方法;我不知道。这暂时可以帮助你。

© www.soinside.com 2019 - 2024. All rights reserved.