c++ - 为什么禁止对位域的非常量引用?

标签 c++ c++11 bit-fields

C++11 中的第 9.6/3 节非常清楚:“非常量引用不应绑定(bind)到位域。”这一禁令背后的动机是什么?

我知道无法将引用直接绑定(bind)到位域。但是如果我这样声明,

struct IPv4Header {
  std::uint32_t version:4,         // assumes the IPv4 Wikipedia entry is correct
                IHL:4,
                DSCP:6,
                ECN:2,
                totalLength:16;
};

为什么我不能说这个?

IPv4Header h;

auto& ecn = h.ECN;

我希望底层代码实际上绑定(bind)到包含我感兴趣的位的整个 std::uint32_t,并且我希望读取和写入操作生成代码以做适当的掩蔽。结果可能很大而且很慢,但在我看来它应该有效。这与标准所说的对 const 位域的引用的工作方式一致(同样来自 9.6/3):

If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly.

这表明写入位域是问题所在,但我不明白它是什么。我考虑了必要的屏蔽可能会在多线程代码中引入竞争的可能性,但是,根据 1.7/3,出于多线程目的,非零宽度的相邻位域被视为单个对象。在上面的示例中,IPv4Header 对象中的所有位域都将被视为单个对象,因此根据定义,试图在读取其他字段的同时修改一个字段的多线程代码已经很活泼了。

我显然遗漏了什么。这是什么?

最佳答案

非常量引用不能绑定(bind)到位域,原因与指针不能指向位域的原因相同。

虽然没有指定引用是否占用存储空间,但很明显,在非平凡的情况下,它们被伪装成指针来实现,而这种引用的实现是语言作者“有意为之”的。就像指针一样,引用必须指向一个可寻址的存储单元。不可能将非常量引用绑定(bind)到不可寻址的存储单元。由于非常量引用需要直接绑定(bind),因此非常量引用不能绑定(bind)到位域。

产生指向位域的指针/引用的唯一方法是实现某种“ super 指针”,除了存储中的实际地址外,它还包含某种位偏移量和位-宽度信息,以告诉编写代码要修改哪些位。请注意,此附加信息必须存在于所有数据指针类型中,因为 C++ 中没有“指向位域的指针/引用”这样的类型。这基本上相当于实现一个更高级别的存储寻址模型,与底层操作系统/硬件平台提供的寻址模型完全分离。出于纯粹的效率考虑,C++ 语言从未打算要求对底层平台进行这种抽象。

一种可行的方法是引入一个单独的指针/引用类别,例如“指向位域的指针/引用”,这将具有比普通数据指针/引用更复杂的内部结构。这些类型可以从普通的数据指针/引用类型转换而来,但反之则不行。但这似乎不值得。

在实际情况下,当我必须处理打包成位和位序列的数据时,我通常更喜欢手动实现位域并避免语言级别的位域。位域的名称是一个编译时实体,不可能进行任何类型的运行时选择。当需要运行时选择时,更好的方法是声明一个普通的 uint32_t 数据字段并手动管理其中的各个位和位组。这种手动“位域”的运行时选择很容易通过掩码和移位(两者都可以是运行时值)来实现。基本上,这接近于手动实现上述“ super 指针”。

关于c++ - 为什么禁止对位域的非常量引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17607967/

相关文章:

c++ - 错误 C2248 : 'CvSVM::CvSVM' : cannot access private member declared in class 'CvSVM'

c++ - 用于 Windows 的 python ncreduce

c++ - 如果互斥体和数据项在内存中靠近在一起,那么缺点在哪里?

c++ - 为什么我不能在从算术运算符返回时将此类作为引用传递?

c++ - union 内位域的对齐

c++ - C++ 风险克隆中的区域

c++ - 如何引导 OGDF 中的边?

c++ - boost::python 和 set::erase -> 奇怪的行为

c++ - 模板编程和位域

c - 在 C 中不使用 "PACKED"编译器指令打包数据