【问题标题】:How to work with bitfields longer than 64 bits?如何处理超过 64 位的位域?
【发布时间】:2011-11-15 15:34:35
【问题描述】:

问题说明了一切。

如果我有 96 位字段:

uint32_t flags[3]; //(thanks @jalf!)

鉴于其中的子字段可能位于 32 位边界(例如,从位 29 到 35 的字段),我如何最好地访问它?

我需要尽可能快地访问,所以我不想将它们作为数组的 32 位元素进行迭代。

【问题讨论】:

  • 您希望在位域上执行什么样的操作?
  • 如果你碰巧在 64 位机器上安装了 gcc、clang 等,你可以使用它们的 128 位数据类型,__uint128_t 左右。
  • @JensGustedt 我曾考虑过这一点,但我需要正好 96 位来实现数据的紧凑性和更好的缓存性能(最后 32 位只会浪费在缓存中)。

标签: c++ c bit-manipulation bit-fields


【解决方案1】:

STL 包含一个处理bitfields of arbitary length 的类:

#include <bitset>

int main() {
  const bitset<12> mask(2730ul); 
  cout << "mask =      " << mask << endl;

  bitset<12> x;

  cout << "Enter a 12-bit bitset in binary: " << flush;
  if (cin >> x) {
    cout << "x =        " << x << endl;
    cout << "As ulong:  " << x.to_ulong() << endl;
    cout << "And with mask: " << (x & mask) << endl;
    cout << "Or with mask:  " << (x | mask) << endl;
  }
}

【讨论】:

  • 在 C++ 开发中,std::bitset 是您问题的答案。
  • 谢谢,但不——我不是问要使用哪种数据结构。每秒投射数亿条光线时,我买不起标准容器。
  • @NickWiggill - 你有理由相信使用std::bitset 比其他方法慢吗?考虑this code,它编译为this assemblerstd::bitset 解决方案具有三个内存负载,两个班次,一个“或”和一个“与”。手卷解决方案有三个负载,两个班次,一个“或”和两个“与”。
  • @Rob 是的,我愿意,因为我已经测试过了。考虑到此配置文件的应用,堆栈抖动和缓存性能影响并非微不足道。现在,如果人们停止标记错误的答案......
  • 其实你使用 uint32_t flags[3];,std::bitset 是 struct { uint32_t flags[3]; },你觉得有什么不同?
【解决方案2】:

[此答案对 C 有效(并且通过扩展,也适用于 C++)。]

独立于平台的方式是适当地应用位掩码和位移。

所以要让你的领域从 29 到 35(含):

  (flags[1] & 0xF)        << 3
| (flags[0] & 0xE0000000) >> 29  // The bitmask here isn't really needed, but I like symmetry!

显然,您可以编写一个类/函数/宏来自动执行此操作。

【讨论】:

  • 我还在消化这个,但这是我一直在寻找的。感谢您使用我的示例在代码中提供答案。
  • 我正在编写一个模板函数来检索任意范围的位时,我意识到它是多么的矫枉过正。如果你编写了一些内联函数,每个字段对应一个带有掩码和移位计数的硬编码,就像你在这里所做的那样,你就完成了。
  • @Mark:如果您有模板功能,您应该将其发布为答案。它肯定比为每个字段硬编码上述内容更通用,并且比宏更安全。
  • @MarkRansom,感谢您的评论。无论如何,制作这些宏的原因是什么?这是 C 的回归吗?
  • @NickWiggill,制作宏或函数可以提高代码的可读性并允许重用,同时降低出现错误的可能性并增强可维护性。宏消除了函数调用的开销,但内联函数做同样的事情,同时更安全,更易于阅读。您的问题同时被标记为 C++ 和 C,而 C 没有内联函数。
【解决方案3】:

位域超过 64 位没有问题。它们甚至可以比你的大得多!

我看到的问题是,您正在访问跨越 32 位边界的成员。这更是一个问题。但老实说,在 64 位平台上,如果您使用 long long 创建位域类型,那么您只需注意 64 位边界。

如果您的动机是让您的访问“尽可能快”,那么在尝试比编译器更聪明之前请三思而后行。如今,它们可以在您甚至不知道的情况下进行优化。我最好的建议是:让您的代码易于阅读和理解。

【讨论】:

    猜你喜欢
    • 2010-09-19
    • 1970-01-01
    • 2011-04-19
    • 2014-05-27
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    相关资源
    最近更新 更多