c++ - 如何在 C++ 中遍历一个类型的每一位

标签 c++ templates data-structures bit-manipulation

我想使用模板用 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/

相关文章:

c++ - 数组初始化函数 : Passing Array as Pointer: C++

c++ - 将转发 lambda 转换为函数指针

c++ - 如何有效地设计多键查找,其中一个键是C++中元素的 vector

javascript - 从 javascript 对象中删除较少的序列计数

c++ - VS2012 MSTest 无法捕获断言, native c++

c++ - 错误在 `./2' : free(): invalid pointer: 0x000000000096044c *** Aborted (core dumped)

c++ - 传递给共享库的模板函数 (c++)

c++ - 基类中使用 this 指针的模板函数

c++ - 如何转换dfs

c++ - 如何在未使用 C++ 连接到 DC 时获取成员计算机的专有名称