位字段与 stdint 定义
所以我用 C++ 编程,据我所知,没有与 stdint.h 等效的 C++。这没问题,因为您可以获取 stdint 的副本并包含它...但我的问题基本上是这样的,
这两段代码之间有什么区别:
struct FREQ{
unsigned int FREQLOHI :16;
//etc...
};
除了
struct FREQ{
uint16_t FREQLOHI;
//etc...
}
位域的明显限制之外,还有什么区别吗?性能/便携性问题?哪个是首选?
So I am programming in C++, and as far as I can tell there is no C++ equivalent to stdint.h. Which is no problem, seeing as you can just grab a copy of stdint and include it... but my question is basically this,
what is the difference between these two pieces of code:
struct FREQ{
unsigned int FREQLOHI :16;
//etc...
};
and
struct FREQ{
uint16_t FREQLOHI;
//etc...
}
other than the obvious limitations of bitfields, is there a performance/portability issue? Which is preferred?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不同之处在于,
unsigned int
在不同平台上的大小可能不同,而 uint16_t 保证具有 16 位宽度。这意味着第一个(位域)结构的实例在不同平台上可能具有不同的大小。此外,位域访问的成本更高,因为它涉及额外的移位和掩码。例如,在 unsigned int 为 32 位宽的笔记本电脑上,第一个结构体为 32 位宽,而第二个结构体为 16 位宽。
就可移植性而言,位字段的情况要干净得多,因为它是一项古老的 C 语言功能,在 1998 年标准化时已包含在 C++ 中 (ISO/IEC 14882:1998)。另一方面,
stdint.h
仅在 1999 年才添加到 C(ISO/IEC 9899:1999 标准),因此不是 C++98 (ISO/IEC 14882:1998) 的一部分。随后,相应的头文件cstdint
被合并到 C++ TR1 中,但它将所有标识符放在std::tr1
命名空间中。 Boost 还提供了标头。最新的 C++ 标准(C++11 又名 ISO/IEC 14882:2011,于 2011 年 9 月发布)包含标头cstdint
并将所有标识符放入std
命名空间。尽管如此,cstdint
仍受到广泛支持。The difference is that
unsigned int
may be of different size on different platforms while uint16_t is guaranteed to have 16 bit width. This means that an instance of the first (bitfield) struct may have different size on different platforms. Also, bitfield access is more expensive since it involves extra shift and mask.For example on laptop where unsigned int is 32-bit wide the first struct is 32-bit wide while the second struct is 16-bit.
When it comes to portability, bit-fields are in a much cleaner situation since it is an old C language feature that was included in C++ when it was standardized in 1998 (ISO/IEC 14882:1998). On the other hand
stdint.h
was added to C only in 1999 (ISO/IEC 9899:1999 standard) and hence is not part of C++98 (ISO/IEC 14882:1998). The corresponding headercstdint
was then incorporated into C++ TR1, but it put all the identifiers instd::tr1
namespace. Boost also offered the header. The most recent C++ standard (C++11 aka ISO/IEC 14882:2011 that went out in September 2011) includes the headercstdint
and it puts all the identifiers into thestd
namespace. Despite this,cstdint
is widely supported.编译器通常倾向于将位域打包在一个字中,从而减少结构的整体大小。这种打包的代价是对位域成员的访问速度变慢。例如:
可能会打包为
每次访问
sixteen_bit
时都会发生移位和按位 &手术。另一方面,如果
这样做,则编译器通常会在字边界对齐成员并将其布局如下:
与位域相比,这会浪费更多空间,但可以更快地访问成员,而无需进行位移位和屏蔽。
以下是一些其他差异:
sizeof
应用于位字段成员。就可移植性而言,这两个选项都应该适用于任何符合标准的编译器。如果您指的是在将结构写入文件或套接字时不同平台之间的二进制可移植性,那么无论哪种情况,所有的赌注都将被取消。
就偏好而言,我会选择使用 uint16_t 而不是位字段,除非有充分的理由将字段打包在一起以节省空间。如果结构中有许多布尔值,我通常会使用位域将这些布尔标志压缩在同一个单词中。
Compilers will generally tend to pack bitfields together in a single word, thus reducing the overall size of your struct. This packing is at the expense of slower access to the bitfield members. For example:
Might be packed as
Each time you access
sixteen_bit
it incurs a shift and bitwise & operation.On the other hand, if you do
then the compiler generally aligns the members at word boundaries and lays it out as something like:
This wastes more space compared to bitfields, but the members can be accessed faster without bit-shifting and masking.
Here are some other differences:
sizeof
to a bitfield member.In terms of portability, both options should work on any standards-compliant compiler. If you mean binary portability between different platforms when writing the struct out to a file or socket, then all bets are off for either case.
In terms of preference, I would opt for using
uint16_t
instead of bitfields, unless there a good reason for packing the fields together to save space. If I have manybool
s inside a struct, I'll generally use bitfields for compressing those boolean flags together in the same word.