解释位测试宏在c++
Explain Bit Test macro in C++
我想弄清楚这段代码是如何工作的,但是我不能得到一个单一的答案。
#define testbit(x, y) ( ( ((const char*) & (x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )
我是新手,所以如果你能想出一个方法用简单的英语解释这个,我将非常感激。
它属于一段代码的X-Plane插件找到https://code.google.com/p/xplugins/source/browse/trunk/Xsaitekpanels/SwitchPanel.cpp?r=38 line=19
宏测试x
中y
-th位的值。您不能直接寻址位,因此代码首先将x
视为字节数组(const char*
强制转换)。
然后查找该位所在的字节。一个字节有8位,所以要除以8。为了追求性能,代码不是简单地除以8,而是使用二进制技巧,右移3位。一般来说,对于无符号x
和y
, x >> y = x/2^y
和x << y = x*2^y
。
y/8
的余数。还有一个小技巧,使用y & 7
而不是更清晰的y % 8
。
有了这些信息,你可以制作一个掩码,一个单开位,0x80
,并将其移位到y%8
-th位测试的位置。掩码对字节进行并和,这里的非零结果表示该位被设置为1,否则为0。
完成@RhythmicFistman的答案
@RhythmicFistman的答案缺少了一小部分,那就是转变的最后一步。
>> (7-((y)&0x07)
步骤确保您只获得1或0的结果。使用这段代码,可以安全地进行如下比较:
if (testbit(varible, 6) == 1) {
// do something
}
如果没有该步骤,testbit
将返回一个位掩码,其中第6位将被设置为1或0,而所有其他位始终被设置为0。这就是目的,但它不是以可移植的方式实现的,参见下面的警告3。
使用此代码可能出现的问题
现在给其他答案添加一些东西。其他答案没有指出一些应该在这里提到的关键字,它们是严格混叠和右移算术。我将在下面以警告的形式加以阐述。
警告1:字节顺序
此代码假设您正在使用大端结构,或者仅希望从字符数组中获得正确的位。
原因是如果你把一个int
转换成一个char
s(字节)的数组,你会在一个大的端序机器和一个小的端序机器上得到不同的结果。
警告2:严格的混叠
宏使用了一个强制转换(const char*) &(x)
,它被设计用来改变(x)
的类型,也就是别名,以便更容易得到正确的位。
这是危险的,原因在这个SO答案中得到了很好的解释。简而言之,如果你用优化编译这段代码,可能会发生奇怪的事情。
关于混叠和指针混叠的维基百科页面也很有用,应该阅读。
警告3:Shift Arithmetic Right
除此之外,这段代码使用右移操作符>>
的方式可能存在潜在的问题。该操作符有两种不同的行为,这取决于它操作的变量是有符号还是无符号。只要你不使用负数,你将是安全的,但这个代码不会保护你免受这个错误。不过,我怀疑你不太可能犯这样的错误,所以使用它应该是可以的。
同样值得一提的是,您正在使用signed char
并将其右移。虽然这可以工作,但我更喜欢unsigned char
,它可以提高可移植性,因为当char
和int
的宽度相同时,它不会冒产生算术移位的风险(这在实践中几乎从来没有发生过)。这是有效的,因为char
被提升为int
的移位,参见这个SO答案的解释。
您看到的是一个宏,它执行以下任务:
(为了)
- 进行位移位到y (value: 3)
- 取x的地址并选择y位置的字符(到字符串x中)
- 在所选字符和0x80之间进行二进制操作
- 向前一个结果(值:y和0x7之间二进制运算的结果)做位移位
- 在前一个结果(值:7 - (y和0x7之间的二进制运算结果))上做位移位
嗯,这对你有帮助吗?我不这么认为!
因为这个宏显然是不合适的,而且有点棘手。
位掩码,二进制操作,二进制移位…
如果你能更准确地解释一下你想要理解的内容,也许我能有所帮助。
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- 尽管测试成功,CppUnit测试核心仍被丢弃.为什么
- 数据成员SFINAE的C++17测试:gcc vs clang
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 为什么二进制搜索在我的测试中不起作用
- 从父数组测试用例构造二叉树失败
- 试图对缓存进行跨步测试,但程序并没有结束
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- OpenGL在启用深度测试时不会丢弃我的碎片
- 为测试目标创建具有不同源文件夹的文件
- 在子目录中使用target_sources()命令时用于单元测试(qtest)的项目结构
- VC++本机单元测试,找不到调试符号
- 换位表导致测试失败(但在游戏中运行良好)
- 用于交叉编译和CMake的预处理器宏的单元测试
- 谷歌测试中的期望值存储在哪里
- 如何在for循环中包含两个索引值的测试条件
- 在cygwin中测试新的boost安装时出现cpp错误
- 使用rdtsc进行基准测试的缺点是什么
- 更正 CMakeList.txt 用于谷歌测试的文件?