【问题标题】:bit fields vs. stdint definitions位域与标准定义定义
【发布时间】:2011-11-06 14:43:05
【问题描述】:

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

这两段代码有什么区别:

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

};

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

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

【问题讨论】:

  • #include 将包含此标头。
  • 您不能简单地“获取副本”。例如,从您的 Visual Studio 编译器中获取一个副本并将其放入 mingw 编译器中可能会出现错误行为。接下来,cstdint 应该是从 C++11 开始的可用标头。
  • 据我所知, 在 2008 年或 2010 年不存在。 @Killian,我在 Visual Studio 工作,你可以在这里找到一份副本:link 这是 Microsoft Visual Studio 的符合 ISO C9x 标准的 stdint.h
  • 如果您的 C++ 编译器缺少 [stdint.h],请使用 Boost 版本。
  • <cstdint><stdint.h> 肯定都带有 MSVC++ 2010。

标签: c++ bit-fields stdint


【解决方案1】:

不同之处在于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++ 标准(2011 年 9 月发布的 C++11 又名 ISO/IEC 14882:2011)包括标题 cstdint 并将所有标识符放入 std 命名空间。尽管如此,cstdint 仍受到广泛支持。

【讨论】:

  • 您没有真正解决unsigned int 是位域这一事实。
【解决方案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 而不是位域,除非有充分的理由将这些域打包在一起以节省空间。如果我在一个结构中有很多 bools,我通常会使用位域将这些布尔标志压缩到同一个单词中。

【讨论】:

  • 难道没有一些关键字“要求”编译器对齐“速度”吗?
  • @muntoo:没有,但可能存在编译器特定的编译指示或属性。
猜你喜欢
  • 2014-10-06
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 2013-11-12
  • 2011-08-01
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
相关资源
最近更新 更多