I found a code segment for a structure as below:

    struct
    {
      __u8 saveable: 1;
      __u8 namespace: 1;
      __u8 changeable: 1;
      __u32 reserved: 29;
    };

I wonder what the difference is between that and the definition as below:

    struct
    {
      __u32 saveable: 1;
      __u32 namespace: 1;
      __u32 changeable: 1;
      __u32 reserved: 29;
    };

这背后有什么可能的原因吗?

推荐答案

尽管包含位字段的对象的分配是由实现定义的,但C标准does规定,如果一个 struct 的连续位字段成员中仍有足够的空间,则应将其打包到同一个"单元"中.

this Draft C11 Standard开始(粗体强调):

6.7.2.1 Structure and union specifiers


11    An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.

因此,在第一个 struct 中,前三个字段could be压缩到一个8位单元中,但第四个字段必须放在一个单独的32位单元中(这可能需要4字节对齐,从而将 struct 的总体大小增加到8字节).What also may be significant in such a case is that padding bytes will be added to the structure, which may cause issues if your code relies on contiguous bits.

然而,在第二种情况下,所有四位字段可以放在single个32位单元中,因此 struct 大小可以减少到只有4个字节.

但请注意,这在编译器和平台之间可能有所不同,特别是,如Compiler Explorer example linked in the comments中所示,一个实现有权为第一个 struct 的前三个成员分配一个32位单元.

在Windows上,使用Visual Studio 2022中的clang cl编译器,在编译和运行以下代码时,我得到了上述 struct 之间的大小差异:

#include <stdint.h>
#include <stdio.h>

struct {
    uint8_t saveable : 1;
    uint8_t namespace : 1;
    uint8_t changeable : 1;
    uint32_t reserved : 29;
} s1;

struct {
    uint32_t saveable : 1;
    uint32_t namespace : 1;
    uint32_t changeable : 1;
    uint32_t reserved : 29;
} s2;

int main()
{
    printf("Size of s1 = %zu\n", sizeof(s1));
    printf("Size of s2 = %zu\n", sizeof(s2));
    return 0;
}

输出:

Size of s1 = 8
Size of s2 = 4

C++相关问答推荐

当办公室阻止Visual Studio时编码和编译C

为什么macOS上的FIFA管道比匿名管道慢8倍?

Apple Libm的罪恶功能

POSIX文件描述符位置

球体—立方体重叠:无、部分或全部?

如何在C中只使用一个带双方括号([i][j])访问语法的malloc来分配动态大小的2d数组?

在struct中调用函数,但struct在void中 *

当打印字符串时,为什么在c中没有使用常量限定符时我会收到警告?

两个连续的语句是否按顺序排列?

如何在c++中包装返回空*的函数

C++中矢量类型定义和数据保护的高效解决方案

如何捕捉只有换行符或空格字符缓冲区的边缘大小写

在C语言中,是否可以使枚举数向后计数?

获取每个循环迭代结束时的当前时间

如何在提取的索引中分配空值?

在编写代码时,Clion比vscode有更多的问题指示器

MacOS下C++的无阻塞键盘阅读

不同原型的危险C函数是可能的

使用fread()函数读取txt文件

创建 makefile 来编译位于不同目录中的多个源文件