我想使用模板用 C++ 编写数字搜索树。为此,给定类型 T 和类型 T 的数据,我必须迭代此数据的位。对整数执行此操作很容易,只需将数字向右移动适当数量的位置,然后将数字“&”为 1,就像此处描述的示例一样 How to get nth bit values .当一个人试图从模板数据中获取第 i 位时,问题就开始了。我写了这样的东西
#include <iostream>
template<typename T>
bool getIthBit (T data, unsigned int bit) {
return ((*(((char*)&data)+(bit>>3)))>>(bit&7))&1;
}
int main() {
uint32_t a = 16;
for (int i = 0; i < 32; i++) {
std::cout << getIthBit (a, i);
}
std::cout << std::endl;
}
这行得通,但我不确定这是否不是未定义的行为。这样做的问题是,要遍历数据的所有位,必须知道其中有多少位,这对于结构数据类型来说很难,因为有填充。比如这里
#include <iostream>
struct s {
uint32_t i;
char c;
};
int main() {
std::cout << sizeof (s) << std::endl;
}
实际数据有 5 个字节,但程序的输出显示它有 8 个字节。我不知道如何获取数据的实际大小,或者是否有可能。这里问了一个关于这个的问题How to check the size of struct w/o padding? ,但答案只是“不要”。
最佳答案
很容易知道一个类型有多少位。正好有 CHAR_BIT * sizeof(T)
。 sizeof(T)
是类型的实际 大小(以字节为单位)。但实际上,在标准 C++ 中并没有一种通用的方法来知道哪些位(类型的一部分)正在填充。
我建议不要尝试支持将填充作为 DST 键的类型。
以下技巧可能适用于查找普通可复制类的填充位:
- 使用
std::memset
将对象的所有位设置为 0。 - 对于没有自己子对象的每个子对象,使用
std::memset
将所有位设置为 1。 - 对于每个子对象都有自己的子对象,递归执行上一步和这一步。
- 检查哪些位保持为 0。
我不确定是否有任何技术保证填充实际上保持为 0,所以这是否有效可能是不确定的。此外,可能存在具有填充的非类,并且所描述的技巧不会检测到这些。 long double
就是典型的例子;不知道还有没有其他的。这可能不会检测到位域下未使用的整数位。
所以,有很多注意事项,但它应该适用于您的示例案例:
s sobj;
std::memset(&sobj, 0, sizeof sobj);
std::memset(&sobj.i, -1, sizeof sobj.i);
std::memset(&sobj.c, -1, sizeof sobj.c);
std::cout << "non-padding bits:\n";
unsigned long long ull;
std::memcpy(&ull, &sobj, sizeof sobj);
std::cout << std::bitset<sizeof sobj * CHAR_BIT>(ull) << std::endl;
关于c++ - 如何在 C++ 中遍历一个类型的每一位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69120467/