是否有一个可移植的替代C ++位字段 [英] Is there a portable alternative to C++ bitfields
问题描述
有许多情况(特别是在低级编程中),其中数据的二进制布局很重要。例如:硬件/驱动程序操作,网络协议等。
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屋!