4

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

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

4

3 回答 3

3

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

我建议您只使用屏蔽和按位运算符..

这个链接

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

于 2010-04-19T01:41:37.033 回答
3

(请注意,所有这些都是 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);

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

于 2010-04-19T02:25:57.160 回答
0

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

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

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

于 2010-04-19T02:03:32.057 回答