1

所以我在用 C++ 编程,据我所知,没有与 stdint.h 等效的 C++。没问题,因为您可以获取 stdint 的副本并将其包含在内......但我的问题基本上是这样的,

这两段代码有什么区别:

struct FREQ{
    unsigned int FREQLOHI :16;
    //etc...

};

struct FREQ{
    uint16_t FREQLOHI;
    //etc...
}

除了位域的明显限制之外,是否存在性能/可移植性问题?哪个是首选?

4

2 回答 2

4

不同之处在于unsigned int不同平台上的大小可能不同,而 uint16_t 保证具有 16 位宽度。这意味着第一个(位域)结构的实例在不同平台上可能具有不同的大小。此外,位域访问更昂贵,因为它涉及额外的移位和掩码。

例如,在 unsigned int 为 32 位宽的笔记本电脑上,第一个结构为 32 位宽,而第二个结构为 16 位。

在可移植性方面,位域的情况要干净得多,因为它是 C++ 在 1998 年标准化(ISO/IEC 14882:1998)时包含在 C++ 中的一个古老的 C 语言特性。另一方面stdint.h,仅在 1999 年才被添加到 C 中(ISO/IEC 9899:1999 标准),因此不是 C++98 的一部分(ISO/IEC 14882:1998)。然后将相应的标头cstdint合并到 C++ TR1 中,但它将所有标识符放在std::tr1命名空间中。Boost还提供了标题。最新的 C++ 标准(2011 年 9 月发布的 C++11 又名 ISO/IEC 14882:2011)包括标头cstdint,并将所有标识符放入std命名空间。尽管如此,cstdint还是得到了广泛的支持。

于 2011-11-06T14:55:13.410 回答
2

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

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而不是位域,除非有充分的理由将这些域打包在一起以节省空间。如果bool结构中有很多 s,我通常会使用位域将这些布尔标志压缩到同一个单词中。

于 2011-11-06T17:06:02.227 回答