如何设置,请清除,C/c + + 中有点切换?

2008-09-07 00:42:17
问题评论:

阅读︰ graphics.stanford.edu/~seander/bithacks.html ,当您将此主机,阅读此一︰ realtimecollisiondetection.net/blog/?p=78

您也可能有兴趣签出位 Twiddler全部 Hacks 位,和聚合的魔术算法.

此链接可帮助我了解如何实际工作这些操作- cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/setBitI.html在此处可以找到更有趣的操作- cs.umd.edu/class/sum2003/cmsc311/Notes

我能轻易地想象这不是自身的问题而产生的很有用的参考指南。考虑到了这儿当我需要信息,一个的位吗。

@glglgl /Jonathon 它有足够的 c + + 这种标记的意义。这是个历史问题有很多的流量,c + + 标记将帮助同事感兴趣的程序员通过 google 搜索找到它。

回答:

设置一些

使用按位 OR 运算符 (||) 来设置一些。

number |= 1 << x;

这将设置位x.

有点清除

使用按位 AND 运算符 (&) 有点清除。

number &= ~(1 << x);

它会清除位x必须反位字符串与按位 NOT 运算符 (~),然后和它。

有点切换

XOR 运算符 (^^) 可用于切换位。

number ^= 1 << x;

它将切换位x.

有些检查

不请自来此,但我也可能会添加它。

若要检查一个位,移动数字 x 到右边,然后按位 AND 它︰

bit = (number >> x) & 1;

这将让位x的值为可变的bit.

更改为xn次位

可使用以下将n次位设置为10 :

number ^= (-x ^ number) & (1 << n);

将设置如果x1,并清除如果x0n.

要注意,在平台上,必须对本机支持位设置/清除 (ex,AVR 微控制器),编译器将经常转换 myByte | = (1 << x) 到本机位设置/清除说明 x 时变,ex: (1 << 5),或 const 符号 x = 5。

位 = & (1 << x);将不置于位 x 的值位位不包含类型 _Bool (< stdbool.h >)。否则,位 =!!(编号 & (1 << x));将...

顺便说一下位改变这里都将静态失败如果number的宽度比int

为什么不要更改到的最后一个bit = (number >> x) & 1

1int ,它进行签名。因此,所有操作这里对有符号数字,不能很好地由标准进行都操作。因此,最好使用1U标准并不保证 2 的补数或算术移位.

使用标准的 c + + 库︰ std::bitset<N> .

增强版本︰ boost::dynamic_bitset .

没有必要将自己︰

#include <bitset>
#include <iostream>

int main()
{
    std::bitset<5> x;

    x[1] = 1;
    x[2] = 0;
    // Note x[0-4]  valid

    std::cout << x << std::endl;
}

[Alpha:] > ./a.out
00010

增强版允许与标准库编译时大小 bitset 运行时调整大小 bitset。

+ 1。不该 std::bitset 克隆从"C",但作者标记他/她"c + +"的问题,如 AFAIK,您的答案是最好...这里 std::vector < bool > 是另一种方法,如果人了解其优点和其缺点

@andrewdotnich︰ 矢量 < bool > (遗憾) 是将值存储为位的专用。请参阅gotw.ca/publications/mill09.htm以获取详细信息。.

也许没有人提到因为这标记嵌入它。在大多数嵌入式系统可以避免 STL 像挠。并提升支持可能是非常稀有鸟发现在大多数嵌入式编译器之间。

@Martin 是非常真实。除了特定的性能 killers STL 和模板等,许多嵌入式的系统甚至避免整个标准库完全,因为它们是以验证这种痛苦。大部分的嵌入分支接纳标准,例如 MISRA,需要静态代码分析工具 (任何软件专业人员应使用此工具顺便说一下,不只是嵌入人)。一般人如果及其的源代码,甚至可以让他们在特定的编译器上具有比运行静态分析整个标准库-通过做更多事情。

@Lundin︰ 您的语句是过分广泛 (因此无用热衷)。我确信我可以找到的情况是它们是真实。这不会更改我的初始点。这两种类都在嵌入式系统中是完全正常的使用 (和我知道使用这些事实的)。有关在嵌入式系统上未使用的 STL/提升您初始点也是错误的。我敢肯定有不使用它们的系统,甚至用到这些谨慎使用这些系统,但说不使用它们是不正确 (因为系统是使用它们)。

另一个选项是使用位域︰

struct bits {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct bits mybits;

(实际上,它的三个 1 位 felds) 3 位字段定义。位操作现在成为一个位 (haha) 更简单︰

若要设置或清除一个位︰

mybits.b = 1;
mybits.c = 0;

若要切换位︰

mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1;  /* all work */

有些检查︰

if (mybits.c)  //if mybits.c is non zero the next line below will execute

这仅适用于固定大小的位字段。否则您必须求助于上一个帖子中描述的位全部技术。

噢,那是什么︰ 1 初始化调用。.

我总是发现使用位域是个好主意。有不能控制订单的位分配 (从顶部或底部),这使得无法将值序列化为稳定/笔记本除了一次一位方式。也是不可能混入位字段,例如进行一次测试的几位掩码的 DIY 的位运算。您当然可以使用 & & 和希望编译器将正确地优化...

位字段是坏的在很多方面,我可以几乎编写一本书而已。实际上我几乎不得不这样做有点字段 MISRA C 法规遵从性所需的程序。MISRA C 强制所有实现定义的行为,将记录在案,所以我最终事情会出错,在位域中编写一个非常论述。位顺序 endia 设置,填充位、 填充字节、 各种其他对齐方式,隐式和显式的类型转换与位域,副如果发出 int 未使用,等等。相反,使用按位运算符的更少的缺陷和可移植代码。位字段是完全多余的。

大多数语言功能,如可以正确使用位域,或可能被滥用。如果需要打包到单个 int 的几个较小的值,位字段可以是非常有用的。另一方面,如果您启动使位字段如何映射到实际包含 int 的假设,您在只问问题。

@endolith︰ 这不会是一个不错的主意。可以让它起作用,但它不一定是可移植到不同的处理器,或不同的编译器或甚至到下一版本的同一个编译器。

有时是值得使用 bits 的enum名称

enum ThingFlags = {
  ThingMask  = 0x0000,
  ThingFlag0 = 1 << 0,
  ThingFlag1 = 1 << 1,
  ThingError = 1 << 8,
}

然后在以后使用的名称亦即编写

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

若要设置,请清除并测试。通过这种方式您隐藏您的代码的其余部分的幻数。

不是我认可 Jeremy 的解决方案。

或者您也可以创建一个clearbits()函数,而不是&= ~为什么使用枚举此?我认为那些创建一组唯一的变量隐藏任意值,但您将明确的值分配给每个。那么什么福利 vs 只定义它们作为变量?

@endolith︰enum的用于相关的常数集返回 c 编程中的一大步。我怀疑与现代编译器const short或任何的唯一好处是它们显式地组合在一起。然后在您需要的东西其他非屏蔽您获得的自动编号。在 c + + 中当然,它们也构成不同的类型,这将使您一些额外内容静态错误检查。

如果没有定义一个常量为每个可能的值的位,将进入未定义的枚举常量。什么是ThingError|ThingFlag1,例如?

如果您使用此方法请记住,枚举常量的始终被签名类型为int由于隐式整数提升或带符号的类型执行按位运算,这可能导致所有方式的细微错误。thingstate = ThingFlag1 >> 1 ,例如将调用实现定义的行为。thingstate = (ThingFlag1 >> x) << y可以调用未定义的行为。等等等等。为安全起见,始终强制转换为无符号类型。

@Lundin︰ 从 C + + 11,您可以设置的基础类型的枚举,例如︰ enum My16Bits: unsigned short { ... };

我可以使用定义在头文件中的宏处理位设置和清除︰

/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1<<(b)))
#define BIT_CHECK(a,b) ((a) & (1<<(b)))

/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK(x,y) (((x) & (y)) == (y))

呃我意识到这是 5 岁的开机自检,但没有参数重复任何这些宏,陶建明

BITMASK_CHECK(x,y) ((x) & (y))必须是((x) & (y)) == (y)否则它将返回错误的结果上多个比特掩码 (例如53) / * 问候所有的 gravediggers 到:)*/

1应为(uintmax_t)1或类似情况下任何人试图long或更大的类型上使用这些宏

请输入您的翻译

How do you set, clear and toggle a single bit in C/C++?

确认取消