首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在有和没有位字段的结构上,sizeof函数是如何工作的?(填充)

在有和没有位字段的结构上,sizeof函数是如何工作的?(填充)
EN

Stack Overflow用户
提问于 2020-05-14 05:54:31
回答 1查看 75关注 0票数 0

我在C++中测试带有位字段的结构的行为,但我遇到了一些令人困惑的事情。我的操作系统是Windows10 x64。

我使用的代码如下:

代码语言:javascript
复制
struct BitFieldTest
{
    bool flag1 : 1;
    bool flag2 : 1;
    bool flag3 : 1;
    bool flag4 : 1;
    unsigned char counter1 : 4;
    unsigned int counter2 : 4;
};

struct NormalFieldTest
{
    bool flag1;
    bool flag2;
    bool flag3;
    bool flag4;
    unsigned char counter1;
    unsigned int counter2;
};
struct NormalFieldTest2
{
    bool flag1;
    bool flag2;
    bool flag3;
    bool flag4;
    unsigned char counter1;
};

int main()
{
    std::cout << "Size of bool: " << sizeof(bool) << std::endl;
    std::cout << "Size of unsigned char: " << sizeof(unsigned char) << std::endl;
    std::cout << "Size of unsigned int: " << sizeof(unsigned int) << std::endl;

    std::cout << "Size of struct with bit field: " << sizeof(BitFieldTest) << std::endl;
    std::cout << "Size of struct without bit field: " << sizeof(NormalFieldTest) << std::endl;
    std::cout << "Size of struct without bit field: " << sizeof(NormalFieldTest2) << std::endl;
    return 0;
}

输出为:

代码语言:javascript
复制
Size of bool: 1
Size of unsigned char: 1
Size of unsigned int: 4
Size of struct with bit field: 8
Size of struct without bit field: 12
Size of struct without bit field 2: 5

我不明白为什么结构的大小是这样的。有人可以解释或分享一些关于这个主题的链接吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-14 06:55:56

仅当位字段的类型相同时,位字段才紧凑在一起。因此,使用以下位字段:

代码语言:javascript
复制
struct Test
{
    char Test1 : 1;
    char Test2 : 1;
    char Test3 : 1;
    char Test4 : 1;
    short Test5 : 4;
}

不是一个字节长,而是四个字节。

这是因为两件事-首先,位字段不会跨越类型边界。字符中的比特字段不能与短码中的比特字段混合。

其次,为了对齐,必须将短字符放置在结构开头的两个字节的边界上。因此,编译器将其更改为:

代码语言:javascript
复制
struct Test
{
    char Test1 : 1;
    char Test2 : 1;
    char Test3 : 1;
    char Test4 : 1;
    char BitPadding : 4;
    char AlignmentPadding;
    short Test5 : 4;
    short BitPadding2 : 12;
}

这会使该结构的长度达到四个字节。

现在我们依次检查每个结构。

代码语言:javascript
复制
struct BitFieldTest
{
    bool flag1 : 1;
    bool flag2 : 1;
    bool flag3 : 1;
    bool flag4 : 1;
    unsigned char counter1 : 4;
    unsigned int counter2 : 4;
};

在这里,flag1flag2flag3flag4都具有相同的类型,并精简为存储在单个字节中的四位值。counter1是一种不同的类型,其自然对齐方式为1,因此它移动到下一个字节边界。counter2也是一种不同的类型,它的自然对齐方式是4,因此它移动到下一个4字节边界。然后,如果我们将各个部分和中间填充的大小相加,我们得到:

1个字节具有4个标志,1个字节具有4位计数器,2个字节具有对齐填充,4个字节具有4位计数器。

这加起来有8个字节,这与编译器报告的完全相同。

第二个结构没有位字段,但显示了对齐问题:

代码语言:javascript
复制
struct NormalFieldTest
{
    bool flag1;
    bool flag2;
    bool flag3;
    bool flag4;
    unsigned char counter1;
    unsigned int counter2;
};

在这里,我们有:

1个字节用于布尔flag1,1个字节用于布尔flag2,1个字节用于布尔flag3,1个字节用于布尔flag4,1个字节用于counter1,3个字节用于对齐填充,4个字节用于counter2。

加起来是12,这也是编译器报告的结果。

第三种结构与第二种结构基本相同,但缺少内部对齐填充:

代码语言:javascript
复制
struct NormalFieldTest2
{
    bool flag1;
    bool flag2;
    bool flag3;
    bool flag4;
    unsigned char counter1;
};

在这里,我们有:

1个字节用于布尔flag1,1个字节用于布尔flag2,1个字节用于布尔flag3,1个字节用于布尔flag4,1个字节用于counter1。

正如编译器所报告的,这总共增加了5个字节。

需要注意的是,内部类型的自然对齐也会泄漏到结构本身。考虑以下结构:

代码语言:javascript
复制
struct TrailingAlignment
{
    int Field1;
    short Field2;
}

这是因为该结构可能在数组中使用,如果长度为6字节,则数组中每隔一项就会包含一个未对齐的Field1,这会在不支持未对齐访问的系统中造成重大问题(如某些ARM类型)。为了避免这种情况,编译器在结构的末尾插入两个字节,以确保数组中此结构的下一个实例将在四个字节的边界上对齐,假设第一个结构正确对齐。

对于NormalFieldTest2不会发生这种情况,因为boolchar的自然对齐是一个字节,所以无论结构在内存中的什么位置,它都将始终对齐。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61785560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档