用C ++解释Bit Test宏

时间:2014-03-27 01:46:49

标签: c++ testing macros c-preprocessor bit

我正在试图弄清楚这段代码是如何工作的,但我无法得到一个答案。

#define testbit(x, y)  ( ( ((const char*) & (x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )

我是新手,所以如果你能找到一种用简体英语解释的方法,我真的很感激。

它属于https://code.google.com/p/xplugins/source/browse/trunk/Xsaitekpanels/SwitchPanel.cpp?r=38行= 19

的X-Plane插件的代码段

3 个答案:

答案 0 :(得分:7)

宏测试yx位的值。您无法直接寻址位,因此代码首先将x视为一个字节数组(const char*强制转换)。

然后查找该位所在的字节。一个字节有8位,所以它除以8.追逐性能,而不是简单地除以8,代码使用右移3位的二进制技巧。通常,对于未签名的xyx >> y = x/2^yx << y = x*2^y

此时您需要测试字节内的位,以便获得y/8的余数。还有一个小技巧,使用y & 7代替更清晰的y % 8

使用此信息,您可以制作一个掩码,一个位,0x80并将其移位到位以测试y%8位。掩码与字节进行AND运算,此处的非零结果表示该位设置为1,否则为0.

答案 1 :(得分:2)

完成@ RhythmicFistman的回答

@ RhythmicFistman的答案缺少一小部分,这是轮班的最后一步。

>> (7-((y)&0x07)步骤确保您只得到1或0的结果。使用此代码可以安全地进行比较,如:

if (testbit(varible, 6) == 1) {
    // do something
}

如果没有该步骤testbit将返回一个位掩码,其中第6位将被设置为1或0,而所有其他位始终设置为0.这是意图,但它没有在什么是便携式方式,请参阅下面的警告3

使用此代码的可能问题

现在为其他答案添加一些东西。其他答案没有指出应在此处提及的一些关键字,它们是strict aliasingshift arithmetic right。我的阐述将以下面的警告形式出现。

警告1:Endianness

此代码假定您使用的是big endian架构,或者只希望从字符数组中获取正确的位。

原因是如果您将int转换为char s(字节)数组,您将在big endian计算机与little endian计算机上获得不同的结果

警告2:Strict Aliasing

宏使用了一个转换(const char*) &(x),它旨在更改(x)的类型a.k.a.别名,以便更容易找到正确的位。

这很危险,其原因在this SO answer中得到了很好的解释。简短的版本是,如果你用优化编译这个代码,可能会发生奇怪的事情。

AliasingPointer Aliasing上的维基百科页面也很有用,应该阅读。

警告3:Shift Arithmetic Right

除此之外,此代码使用右移位运算符>>的方式可能存在潜在问题。此运算符有两种不同的行为,具体取决于它所操作的变量是 signed 还是 unsigned 。只要你从不使用负数,你就会安全,但这段代码不能保护你免受这个错误的影响。我怀疑,你不太可能犯这样的错误,所以应该可以使用它。

另外值得一提的是,您正在使用signed char并正在改变它。虽然这样可行,但我更希望unsigned char能提高可移植性,因为当charint宽度相同时,它不会产生算术移位的风险(实际上几乎不是这种情况) ,授予)。这是有效的,因为char升级为int,请参阅this SO answer以获取解释。

答案 2 :(得分:0)

你看到的是一个宏,它可以完成以下工作:

(按顺序)

  • 稍微转移到y(值:3)
  • 取x的地址并选择位置y中的字符(进入字符串x)
  • 在所选字符和0x80
  • 之间进行二进制运算
  • 转移到前一个结果(值:y和0x7之间的二进制运算结果)
  • 对前一个结果进行一次移位(值:7 - (y和0x7之间的二进制运算结果))
嗯,这对你有帮助吗?我不这么认为!

因为这个宏非常不合适,而且有点棘手。

位掩码,二进制运算,二进制移位......

如果你能更准确地解释一下你想要了解的内容,也许我可以提供帮助。