位字段与 stdint 定义

发布于 2024-12-13 17:05:35 字数 327 浏览 0 评论 0原文

所以我用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柳絮泡泡 2024-12-20 17:05:35

不同之处在于,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 header cstdint was then incorporated into C++ TR1, but it put all the identifiers in std::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 header cstdint and it puts all the identifiers into the std namespace. Despite this, cstdint is widely supported.

那支青花 2024-12-20 17:05:35

编译器通常倾向于将位域打包在一个字中,从而减少结构的整体大小。这种打包的代价是对位域成员的访问速度变慢。例如:

struct Bitfields
{
    unsigned int eight_bit : 8;
    unsigned int sixteen_bit : 16;
    unsigned int eight_bit_2 : 8;
};

可能会打包为

0            8                        24
-----------------------------------------------------
| eight_bit  | sixteen_bit            | eight_bit_2 |
-----------------------------------------------------

每次访问 sixteen_bit 时都会发生移位和按位 &手术。

另一方面,如果

struct NonBitfields
{
    uint8_t eight_bit;
    uint16_t sixteen_bit;
    uint8_t eight_bit_2;
};

这样做,则编译器通常会在字边界对齐成员并将其布局如下:

0            8           16           24
-----------------------------------------------------
| eight_bit  |            | sixteen_bit             |
-----------------------------------------------------
| eight_bit_2|                                      |
-----------------------------------------------------

与位域相比,这会浪费更多空间,但可以更快地访问成员,而无需进行位移位和屏蔽。


以下是一些其他差异:

  • 您不能将 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:

struct Bitfields
{
    unsigned int eight_bit : 8;
    unsigned int sixteen_bit : 16;
    unsigned int eight_bit_2 : 8;
};

Might be packed as

0            8                        24
-----------------------------------------------------
| eight_bit  | sixteen_bit            | eight_bit_2 |
-----------------------------------------------------

Each time you access sixteen_bit it incurs a shift and bitwise & operation.

On the other hand, if you do

struct NonBitfields
{
    uint8_t eight_bit;
    uint16_t sixteen_bit;
    uint8_t eight_bit_2;
};

then the compiler generally aligns the members at word boundaries and lays it out as something like:

0            8           16           24
-----------------------------------------------------
| eight_bit  |            | sixteen_bit             |
-----------------------------------------------------
| eight_bit_2|                                      |
-----------------------------------------------------

This wastes more space compared to bitfields, but the members can be accessed faster without bit-shifting and masking.


Here are some other differences:

  • You can't apply sizeof to a bitfield member.
  • You can't pass a bitfield member by reference.

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 many bools inside a struct, I'll generally use bitfields for compressing those boolean flags together in the same word.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文