C 位数组宏,谁能解释一下它们是如何工作的?

发布于 2025-01-05 07:20:22 字数 398 浏览 5 评论 0原文

我正在尝试为学校项目实现埃拉托斯特尼筛,我决定使用位数组来实现。当我寻找材料时,我遇到了这 3 个宏,它们工作完美,但我无法真正阅读(理解)它们。

#define ISBITSET(x,i) ((x[i>>3] & (1<<(i&7)))!=0)
#define SETBIT(x,i) x[i>>3]|=(1<<(i&7));
#define CLEARBIT(x,i) x[i>>3]&=(1<<(i&7))^0xFF;

您能否详细地向我解释至少其中之一,我对 C 中的按位运算有非常基本的了解(基本上我知道它们“存在”)。

这可以在使用不同字节序的另一个架构上工作吗? 提前致谢。

I'm trying to implement sieve of erathostenes for school project and I've decided to do so using bit arrays. While I was searching for materials, I came across these 3 macros, they work flawlessly, but I can't really read(understand) them.

#define ISBITSET(x,i) ((x[i>>3] & (1<<(i&7)))!=0)
#define SETBIT(x,i) x[i>>3]|=(1<<(i&7));
#define CLEARBIT(x,i) x[i>>3]&=(1<<(i&7))^0xFF;

Could you please explain to me at least one of them in detail, I have very basic knowledge about bitwise operations in C (basically I know they "exist").

Will this work on another architecture using different endianness?
Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅沫记忆 2025-01-12 07:20:22

x是字符数组。 i 是位索引。由于每个 char 都是 8 位,因此 i 的最后 3 位定义了 char 中的位,其余位定义了数组中的 char。

i>>3 将 i 向右移动 3 位,这样您就得到了告诉您哪个字符的部分,因此 x[i>>3] 就是该字符包含由i索引的位。

i&7i 的最后 3 位(因为 710==1112< /code>),所以它是字符中位的索引。 1<<(i&7) 是一个 char(实际上它是 int,但在这种情况下您可以忽略差异),它具有由 i 索引的位,其余部分关闭。 (位掩码)

char&mask 是检查位是否打开的常用方法。

char|=mask 是打开位的常用方法。

char&=~mask 是关闭位的常用方法,如果 mask 是 char,则 ~mask==mask^0xFF

我不认为这些宏是依赖字节序的。 (如果您通过将 int[] 转换为 *char 获得 x,则情况不同)

xis array of chars. i is an index of bits. since every char is 8 bits, the last 3 bits of i define the bit in the char, and the rest bits define the char in the array.

i>>3 shift i 3 bits to the right, so you get the part that tell you which char, so x[i>>3] is the char that contain the bit indexed byi.

i&7 is the last 3 bits of i (since 710==1112), so it's the index of the bit in the char. 1<<(i&7) is a char (truly it's int, but in this context you can ignore the difference), that has the bit indexed by i on, and the rest bits off. (the mask of the bit)

char&mask is the common way to check if bit is on.

char|=mask is the common way to turn bit in.

char&=~mask is the common way to turn bit off, and if mask is char, then ~mask==mask^0xFF.

I don't think that these macros are endiannes-depend. (if you got x by converting int[] to *char, it's a different story)

苏大泽ㄣ 2025-01-12 07:20:22

首先,这些宏邪恶地假设 CHAR_BIT == 8i >>> 。 3 实际上是i / 8。 (所以实际上这段代码应该是 i / CHAR_BIT。)第一个表达式计算包含所需位的 byte,因此是数组 中的数组索引x(应该是一个unsigned char数组!)。

现在我们已经选择了正确的字节,即 x[i >>>; 3](或者用您自己的更好的代码中的x[i / CHAR_BIT]),我们必须进行位调整。再说一遍,i & 7 确实希望成为 i % CHAR_BIT,并且它仅提取位计数的剩余部分,从而为您提供字节内的偏移量。

示例。使用 i = 43 请求第 44 位,并假设 CHAR_BIT = 8i / CHAR_BIT 为 5 ,所以我们在第六个字节,并且 i % CHAR_BIT 是 3,所以我们正在查看第六个字节的第四位。

实际的位摆弄本身做了通常的事情;例如,对给定位的测试使用适当的位模式执行按位与(即第 k 位的 1 << k);设置该位使用按位或,而将其归零则需要更多的参与(想一想!)。

First off, those macros assume evilly that CHAR_BIT == 8, and i >> 3 is actually i / 8. (So really this code should say i / CHAR_BIT.) This first expression computes the byte which contains your desired bit, and is thus the array index in your array x (which should be an array of unsigned char!).

Now that we've selected the correct byte, namely x[i >> 3] (or x[i / CHAR_BIT] in your own, better code), we have to do the bit-fiddling. Again, i & 7 really wants to be i % CHAR_BIT, and it extracts only the remainder of your bit count that gives you the offset within the byte.

Example. Requesting the 44th bit with i = 43, and assuming CHAR_BIT = 8, i / CHAR_BIT is 5, so we're in the sixth byte, and i % CHAR_BIT is 3, so we're looking at the fourth bit of the sixth byte.

The actual bit-fiddling itself does the usual stuff; e.g. testing for a given bit performs bit-wise AND with the appropriate bit pattern (namely 1 << k for the kth bit); setting the bit uses bit-wise OR, and zeroing it requires something a tiny bit more involved (think about it!).

关于从前 2025-01-12 07:20:22
#define ISBITSET(x,i) (((x)[(i) / CHAR_BIT] & (1u << ((i) % CHAR_BIT))) != 0)
#define SETBIT(x,i) (x)[(i) / CHAR_BIT] |= (1u << ((i) % CHAR_BIT);
#define CLEARBIT(x,i) (x)[(i) / CHAR_BIT] &= ~(1u << ((i) % CHAR_BIT))
  • 总是在宏参数两边加上括号,
  • 对于位操作总是更喜欢无符号类型
  • (1u << CHAR_BIT)对于 8 位平台来说是 256,
  • 最后一个宏后面有一个额外的 ;
#define ISBITSET(x,i) (((x)[(i) / CHAR_BIT] & (1u << ((i) % CHAR_BIT))) != 0)
#define SETBIT(x,i) (x)[(i) / CHAR_BIT] |= (1u << ((i) % CHAR_BIT);
#define CLEARBIT(x,i) (x)[(i) / CHAR_BIT] &= ~(1u << ((i) % CHAR_BIT))
  • Always put parenthesis around macro arguments
  • always prefer unsigned types for bit operations
  • (1u << CHAR_BIT) is 256 for 8 bit platforms
  • there was an exra ; after the last macro
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文