是否有一个可移植的替代C ++位字段 [英] Is there a portable alternative to C++ bitfields

查看:137
本文介绍了是否有一个可移植的替代C ++位字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有许多情况(特别是在低级编程中),其中数据的二进制布局很重要。例如:硬件/驱动程序操作,网络协议等。

There are many situations (especially in low-level programming), where the binary layout of the data is important. For example: hardware/driver manipulation, network protocols, etc.

在C ++中,我可以使用 char * 和按位操作(屏蔽和移位),但是这是冗长乏味和容易出错。显然,我试图限制这些操作的范围,并将它们封装在更高级的API中,但它仍然是一个痛苦。

In C++ I can read/write arbitrary binary structures using char* and bitwise operations (masks and shifts), but that's tedious and error-prone. Obviously, I try to limit the scope of these operations and encapsulate them in higher-level APIs, but it's still a pain.

C++ bitfields 似乎为这个问题提供了一个开发人员友好的解决方案,但不幸的是,它们的存储是实现特定

C++ bitfields seem to offer a developer-friendly solution to this problem, but unfortunately their storage is implementation specific.

NathanOliver提到 std :: bitset ,它基本上允许你用一个好的 operator [] 访问整数的单个位,但缺少多位字段的访问器。

NathanOliver mentionned std::bitset which basically allows you to access individual bits of an integer with a nice operator[] but lacks accessors for multi-bit fields.

使用元编程和/或宏,可以抽象库中的逐位操作。由于我不想重新发明轮子,我正在寻找一个(最好是STL或boost)库,这样做。

Using meta-programming and/or macros, it's possible to abstract the bitwise operations in a library. Since I don't want to reinvent the wheel, I'm looking for a (preferably STL or boost) library that does that.

我正在调查这是一个 DNS 解析器,但是问题及其解决方案应该是通用的。

For the record, I'm looking into this for a DNS resolver, but the problem and its solution should be generic.

编辑:短解答:结果是位字段的存储是可靠的

short answer: it turns out bitfield's storage is reliable in practice (even if it's not mandated by the standard) since system/network libraries use them and yeild well behaved programs when compiled with mainstream compilers.

推荐答案

从C ++ 14标准(N3797草案),第9.6节[class.bit],第1段:

From the C++14 standard (N3797 draft), section 9.6 [class.bit], paragraph 1:


类对象中位字段的分配是实现定义的。
位字段的对齐是由实现定义的。比特字段被打包到某个可寻址分配单元中。
[注意:位字段跨一些机器上的分配单元,而不在其他机器上。位字段在一些机器上从右到左分配,在其他机器上从左到右分配。 - end note]

Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. [ Note: Bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. — end note ]

虽然注释是非规范的,但我知道的每个实现都使用两种布局之一: endian或little endian位顺序。

Although notes are non-normative, every implementation I'm aware of uses one of two layouts: either big-endian or little endian bit order.

请注意:


  • 手动填充。这意味着你必须知道你的类型的大小(例如通过使用< cstdint> )。


  • 用于检测位顺序的预处理器宏是与实现相关的。

  • 通常,位顺序字节顺序与字节顺序字节顺序相同。我相信有一个编译器标志来覆盖它,但是我找不到它。

  • You must specify padding manually. This implies that you must know the size of your types (e.g. by using <cstdint>).
  • You must use unsigned types.
  • The preprocessor macros for detecting the bit order are implementation-dependent.
  • Usually the bit order endianness is the same as the byte order endianness. I believe there is a compiler flag to override it, though, but I can't find it.

例如, code> netinet / tcp.h 和其他附近的标头。

For examples, look in netinet/tcp.h and other nearby headers.

由OP编辑:例如 tcp .h 定义

struct
{
    u_int16_t th_sport;     /* source port */
    u_int16_t th_dport;     /* destination port */
    tcp_seq th_seq;     /* sequence number */
    tcp_seq th_ack;     /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int8_t th_x2:4;       /* (unused) */
    u_int8_t th_off:4;      /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
    u_int8_t th_off:4;      /* data offset */
    u_int8_t th_x2:4;       /* (unused) */
# endif
    // ...
}


b $ b

由于它与主流编译器配合使用,意味着bitset的内存布局在实践中是可靠的。

And since it works with mainstream compilers, it means bitset's memory layout is reliable in practice.

编辑:

这是在一个字节序中可移植的:

This is portable within one endianness:

struct Foo {
    uint16_t x: 10;
    uint16_t y: 6;
};

但这可能不是因为它跨越一个16位单位:

But this may not be because it straddles a 16-bit unit:

struct Foo {
    uint16_t x: 10;
    uint16_t y: 12;
    uint16_t z: 10;
};

这可能不是因为它有隐含的填充:

And this may not be because it has implicit padding:

struct Foo {
    uint16_t x: 10;
};

这篇关于是否有一个可移植的替代C ++位字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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