参见在线示例: Ideone example
struct {
union {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint32_t rawID : 29;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
为什么编译器会将结构的大小报告为5个字节而不是4个?它应该包含32位。
答案 0 :(得分:6)
问题是__attribute__((packed))
没有执行按位打包。它只是保证struct
成员之间没有填充。您可以尝试这个更简单的示例,其中size也报告为5:
typedef struct structTag {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
按位打包仅适用于位域成员。您需要将结构重新设计为结构与bitfields messageID / priority / canFlags的结合,以及带有bitfields rowID / canFlags的结构。换句话说,您需要复制或使用访问器宏或成员函数。
答案 1 :(得分:5)
由于内存对齐:编译器不能在一个字节的中间中启动canFlags
,它会在开头启动它下一个字节(可能是*)。因此,初始联合有四个字节,canFlags
有一个字节。
例如,如果您将canFlags
移动到联合中,它(可能*)的大小为4:
typedef struct structTag {
union {
struct {
uint32_t messageID : 26; /* 26bit message id, 67108864 ids */
uint8_t priority : 3; /* priority: MUST BE 0 */
} __attribute__ ((packed));
uint32_t rawID : 29;
uint8_t canFlags : 3; /* <==== Moved */
} __attribute__ ((packed));
} __attribute__ ((packed)) idSpecial;
Updated example on ideone。显然,这种具体的改变可能并不是你想要的;我只是证明问题是开始一个不在字节边界上的新字段。
*&#34;可能&#34;因为最终它取决于编译器。
答案 2 :(得分:1)
使用数据结构对齐在计算机内存中排列和访问数据。其中有两个相关问题
当计算机执行写操作时,它通常以4个字节的倍数写入(对于32位系统)。这一行为的一个原因是提高绩效的目标。因此,当您编写任何数据结构时,它具有前1个字节变量,然后是4个字节的可变数据,它将在第一个1字节数据之后进行填充,以便在32位边界上对齐它。
struct {
union {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint32_t rawID : 29;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
现在在上面的数据结构中,您正在使用__attribute__ ((packed))
,这意味着没有填充。所以uint32_t是4个字节,但是你说它有26位和3位优先级。现在,因为在一个结构中有两个变量,所以它将保留32位而不是29位,这样您的第一个结构的信息就会在边界上进行分配。
现在对于canFlags它将需要另一个字节。所以这使得5个字节而不是4个。
答案 3 :(得分:0)
在某些编译器中,要“合并”这些位,所有项必须属于同一类型。所以现在让uint32_t
成为uint8_t
- 这似乎不是编译器中的情况.IdeOne使用了'
[无论如何,编译器如何合并这些位仍然取决于它,因此绝对保证数据存储为32位的唯一方法是使用单个uint32_t
并声明执行相关移位和/或操作值的类 - 唯一的保证是你的结构中的一个元素至少具有你所要求的位数]
正如其他人所指出的那样,除了字节边界之外,你无法启动新结构。我通过在union中包含第二个结构来修复它,如下所示: http://ideone.com/Mr1gjD
#include <stdint.h>
#include <stdio.h>
typedef struct structTag {
union {
struct {
uint32_t messageID : 26; /* 26bit message id, 67108864 ids */
uint8_t priority : 3; /* priority: MUST BE 0 */
} __attribute__ ((packed));
struct {
uint32_t rawID : 29;
uint8_t canFlags : 3;
};
} __attribute__ ((packed));
} __attribute__ ((packed)) idSpecial;
int main() {
printf("size: %d", sizeof(idSpecial));
return 0;
}