为什么禁止非常量引用位域? [英] Why are non-const references to bitfields prohibited?

查看:197
本文介绍了为什么禁止非常量引用位域?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++ 11中的9.6 / 3节非常清楚:非常量引用不应绑定到位域。

Section 9.6/3 in C++11 is unusually clear: "A non-const reference shall not be bound to a bit-field." What is the motivation behind this prohibition?

我知道禁止将引用直接绑定到位域是不可能的。但是,如果我声明这样的话,

I understand that it's not possible to directly bind a reference to a bitfield. But if I declare something like this,

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;

我希望底层代码实际上绑定到整个 std: :uint32_t 包含我感兴趣的位,我希望读写操作可以生成代码以进行适当的屏蔽。结果可能很大且很慢,但是在我看来,它应该可以工作。这将与标准所说的引用 const 位域的方式保持一致(同样是9.6 / 3):

I'd expect the underlying code to actually bind to the entire std::uint32_t that contains the bits I'm interested in, and I'd expect read and write operations to generate code to do the appropriate masking. The result might be big and slow, but it seems to me that it should work. This would be consistent with the way the Standard say that references to const bitfields work (again from 9.6/3):

如果引用
的初始化类型为const T&是一个引用位字段的左值,该引用绑定到一个临时初始化为
来保存该位字段的值;

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 对象中的所有位字段都将被视为单个对象,因此,按照定义,尝试修改字段同时读取其他字段的多线程代码将已经定义为

This suggests that writing to bitfields is the problem, but I don't see what it is. I considered the possibility that the necessary masking could introduce races in multithreaded code, but, per 1.7/3, adjacent bitfields of non-zero width are considered a single object for purposes of multithreading. In the example above, all the bitfields in an IPv4Header object would be considered a single object, so multithreaded code attempting to modify a field while reading other fields would, by definition, already be racy.

我显然缺少了一些东西。是什么?

I'm clearly missing something. What is it?

推荐答案

非常量引用由于指针不能相同的原因而不能绑定到位域

Non-const references can't be bound to bit-fields for the same reason pointers can't point to bit-fields.

虽然未指定引用是否占用存储空间,但很明显,在非平凡的情况下,它们是伪装成指针的,这语言的作者打算执行引用。就像指针一样,引用必须指向可寻址的存储单元。将非常量引用绑定到不可寻址的存储单元是不可能的。由于非常量引用需要直接绑定,因此非常量引用不能绑定到位域。

While it is not specified whether references occupy storage, it is clear that in non-trivial cases they are implemented as pointers in disguise, and this implementation of references is "intended" by the authors of the language. And just like pointers, references have to point to an addressable storage unit. It is impossible to bind a non-const reference to a storage unit that is not addressable. Since non-const references require direct binding, a non-const reference cannot be bound to a bit-field.

生成指针的唯一方法到位字段的实现将是实现某种超级指针,该超级指针除了存储中的实际地址外还将包含某种位偏移和位宽信息,以便告诉编写代码修改哪些位。请注意,所有数据指针类型都必须包含此附加信息,因为C ++中没有指针/对位字段的引用这样的类型。从根本上讲,这等效于实现更高级别的存储寻址模型,这与底层OS /硬件平台提供的寻址模型完全分离。 C ++语言从不打算出于纯粹的效率考虑而要求从底层平台进行这种抽象。

The only way to produce a pointer/reference that can point to bit-fields would be to implement some sort of "superpointer" that in addition to the actual address in storage would also contain some sort of bit-offset and bit-width information, in order to tell the writing code which bits to modify. Note that this additional information would have to be present in all data pointer types, since there's no such type in C++ as "pointer/reference to bit-field". This is basically equivalent to implementing a higher-level storage addressing model, quite detached from the addressing model provided by the underlying OS/hardware platform. C++ language never intended to require that sort of abstraction from the underlying platform out of pure efficiency considerations.

一种可行的方法是引入一种单独的指针/引用类别,例如作为位域的指针/引用,它的内部结构比普通数据指针/引用更复杂。这样的类型可以从普通的数据指针/引用类型转换而来,但是不能反过来。

One viable approach would be to introduce a separate category of pointers/references such as "pointer/reference to bit-field", which would have a more complicated inner structure than an ordinary data pointer/reference. Such types would be convertible from ordinary data pointer/reference types, but not the other way around. But it doesn't seem to be worth it.

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

In practical cases, when I have to deal with data packed into bits and sequences of bits, I often prefer to implement bit-fields manually and avoid language-level bit-fields. The name of bit-field is a compile-time entity with no possibility of run-time selection of any kind. When run-time selection is necessary, a better approach is to declare an ordinary uint32_t data field and manage the individual bits and groups of bits inside it manually. The run-time selection of such manual "bit-field" is easily implemented through masks and shifts (both can be run-time values). Basically, this is close to manual implementation of the aforementioned "superpointers".

这篇关于为什么禁止非常量引用位域?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆