【问题标题】:How can I get bitfields to arrange my bits in the right order?如何让位域以正确的顺序排列我的位?
【发布时间】:2010-04-19 01:37:28
【问题描述】:

首先,有问题的应用程序总是在同一个处理器上,编译器总是 gcc,所以我不担心位域不可移植。

gcc 对位域进行布局,使第一个列出的域对应于字节的最低有效位。所以下面的结构,a=0, b=1, c=1, d=1,你得到一个字节值 e0。

struct Bits {
  unsigned int a:5;
  unsigned int b:1;
  unsigned int c:1;
  unsigned int d:1;
} __attribute__((__packed__));

(其实这是C++,所以说的是g++。)

现在假设我希望 a 是一个六位整数。

现在,我明白为什么这不起作用了,但我编写了以下结构:

struct Bits2 {
  unsigned int a:6;
  unsigned int b:1;
  unsigned int c:1;
  unsigned int d:1;
} __attribute__((__packed__));

bcd设置为1,a设置为0会导致以下两个字节:

c0 01

这不是我想要的。我希望看到这个:

e0 00

有没有办法指定一个结构,它在第一个字节的最高有效位中有 3 位,在第一个字节的 5 个最低有效位和第二个字节的最高有效位中有 6 个位?

请注意,我无法控制这些位的布局位置:这是由其他人的界面定义的位布局。

【问题讨论】:

  • "gcc 对位域进行布局,使第一个列出的域对应于字节的最低有效位。"不,GCC(在这种情况下包括 g++,它继承了 C 实现定义的行为)以 ABI 相关的顺序布置位域:gcc.gnu.org/onlinedocs/gcc/…。这是否恰好对您的架构进行 lsbit-up 纯属偶然。

标签: c++ c gcc bit-fields


【解决方案1】:

(请注意,所有这些都是 gcc 特定的评论 - 我很清楚位域的布局是实现定义的)。

不在 little-endian 机器上:问题在于,在 little-endian 机器上,第二个字节的最高有效位不被认为与第一个字节的最低有效位“相邻”。

但是,您可以将位域与ntohs() 函数结合起来:

union u_Bits2{
    struct Bits2 {
      uint16_t _padding:7;
      uint16_t a:6;
      uint16_t b:1;
      uint16_t c:1;
      uint16_t d:1;
    } bits __attribute__((__packed__));
    uint16_t word;
}

union u_Bits2 flags;
flags.word = ntohs(flag_bytes_from_network);

但是,我强烈建议您避免使用位域,而是使用移位和掩码。

【讨论】:

  • 我想你的意思是“注意小端”,而不是“不在小端”。不过我想我明白你在说什么。在 little-endian 机器上,位的邻接性取决于位如何打包到机器字中,并且编译器假定机器字将被字节交换。我将听取其他人的建议并进行屏蔽和转换,但感谢您了解这里发生了什么。
  • 是的 - gcc 将 word 中的位域从最低位到最高位打包 - 在小端机器上,最低 8 位存储在第一个字节中。
【解决方案2】:

通常你不能对联合的打包方式做出强有力的假设,每个编译器实现可能会选择以不同的方式打包它(以节省空间或对齐字节内的位域)。

我建议您只使用掩码和按位运算符..

来自this link

位域的主要用途是允许紧密打包数据或能够在某些外部生成的数据文件中指定字段。 C 不保证机器字中字段的顺序,所以如果你出于后一个原因使用它们,你的程序不仅是不可移植的,它也会依赖于编译器。该标准称字段被打包到“存储单元”中,这些单元通常是机器字。打包顺序,以及位域是否可以跨越存储单元边界,由实现定义。为了强制对齐存储单元边界,在您想要对齐的边界之前使用一个零宽度字段。

【讨论】:

    【解决方案3】:

    C/C++ 无法指定结构的逐位内存布局,因此您需要对 8 位或 16 位(无符号)整数(来自 <stdint.h> 或 @987654322 的 uint8_t、uint16_t 进行手动位移和屏蔽@)。

    在我所知道的十几种编程语言中,只有极少数允许您为位域指定逐位内存布局:Ada、Erlang、VHDL(和 Verilog)。

    (如果您想在该列表中添加更多语言,请访问社区 wiki。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 2017-01-31
      相关资源
      最近更新 更多