位域类型是否影响结构体对齐方式?

3

我有以下结构:

struct bf_struct1
{
    uint64_t bf1 : 1;
    uint64_t bf2 : 6;
    uint64_t bf3 : 2;
    uint64_t bf4 : 55;
}

struct bf_struct2
{
    uint8_t bf1 : 1;
    uint8_t bf2 : 6;
    uint8_t bf3 : 2;
    uint64_t bf4 : 55;
}

结构成员的对齐是否取决于位字段成员的类型?

1
sizeof()告诉你这两个结构体的大小是多少?如果它们都是8,我会回答“不是”。 - Charlie Burns
5个回答

2
#include <stdio.h>

#define uint64_t unsigned long long
#define uint8_t unsigned char

struct bf_struct1
{
    uint64_t bf1 : 1;
    uint64_t bf2 : 6;
    uint64_t bf3 : 2;
    uint64_t bf4 : 55;
};

struct bf_struct2
{
    uint8_t bf1 : 1;
    uint8_t bf2 : 6;
    uint8_t bf3 : 2;
    uint64_t bf4 : 55;
};
int main(){
    printf("%lu ", sizeof(struct bf_struct1));
    printf("%lu ", sizeof(struct bf_struct2));
    return 0;
}

结果是8 16。所以我会说答案是肯定的。虽然gcc和clang在我的机器上达成了一致,但取决于编译器。您可以创建一些联合体并确定对齐方式。


这对于每个编译器和每个系统都是不同的。位域在标准中定义得非常不清楚。 - Lundin

2
Does the structure member alignment depend on type of a bitfield members?  

可以。

检查 字节偏移量位偏移量

然而,包含位字段的聚合体的对齐规则取决于生效的对齐模式。
enter image description here

这些规则在这里描述


2
  • 整个位域的对齐方式是未指定行为,位域是否允许分配不对齐是实现定义的行为。
  • 位域的位顺序是实现定义的。
  • 由于上述两点,编译器可以自由地在位域内任意添加填充位和填充字节,以实现定义的方式。
  • uint64_t 是否实际允许在位域内使用是实现定义的。因此,代码可能甚至无法正常工作。

如果没有阅读特定编译器的文档,实际上无法确定这段代码将会做什么,更不用说它如何受到对齐的影响了。


1
是的,它会影响到它。在第一个示例中,所有字段都可以适合单个64位uint64_t,因此该结构体可能总共需要8字节。但是,在第二个示例中,它可能总共需要16字节。前三个字段至少需要两个字节(两个uint8_t)。然后,55位的最后一位域将使用一个单独的uint64_t,该值可能对齐到8字节边界上。因此,实际布局取决于编译器,但是在两个示例中位的位置会有所不同(因为在第二个示例中,uint64_t之前假定填充)。

布局可能类似于以下内容(不完全按比例):

bf_struct1

+---------------+---------+---------+-----------------------------------+
|    uint8_t    | uint8_t | Padding | uint64_t                          |
+---------------+---------+---------+-----------------------------------+
| bf1, bf2, bf3           | 48-bits | bf4                               |
+---------------+---------+---------+-----------------------------------+

bf_struct2
+-----------------------------------+
|      uint64_t                     |
+-----------------------------------+
| bf1, bf2, bf3, bf4                |
+-----------------------------------+

1

来自权威解释

6.7.2.1 结构体和联合体说明符
...
5 位域必须具有限定或未限定版本的类型,如 _Bool, signed int, unsigned int 或其他某种实现定义的类型。原子类型是否允许是由实现定义的。
...
11 实现可以分配任何足以容纳位域的可寻址存储单元的地址。如果还有足够的空间,则在结构中紧随另一个位域后面的位域应被打包到同一单元的相邻位中。如果剩余空间不足,则位于下一个单元中的不适合的位域或与相邻单元重叠的位域是否被放置是由实现定义的。在单元内分配位域的顺序(高位到低位或低位到高位)是由实现定义的。可寻址存储单元的对齐方式未指定。

简短回答:取决于实现,它可以。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接