如何获得位域以正确的顺序排列我的位?

时间:2010-04-19 01:37:29

标签: c++ c gcc bit-fields

首先,有问题的应用程序总是在同一个处理器上,编译器总是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__));

b c d 设置为1,将 a 设置为0会导致以下两个字节数:

c0 01

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

e0 00

有没有办法指定一个结构,在第一个字节的最高有效位中有三个位,六个位跨越第一个字节的五个最低有效位和第二个字节的最高有效位?

请注意,我无法控制这些位应该布局的位置:它是由其他人的接口定义的位布局。

3 个答案:

答案 0 :(得分:3)

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

我建议你只使用屏蔽和按位运算符。

来自this link

  

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

答案 1 :(得分:3)

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

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

但是,您可以将位域与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);

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

答案 2 :(得分:0)

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

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

(社区维基,如果您想在该列表中添加更多语言。)