c - C 结构体中的位域表达式

标签 c struct

我找到了如下结构的代码段:

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

我想知道它和下面的定义有什么区别:

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

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

最佳答案

虽然包含位域的对象的分配是实现定义的,但 C 标准确实指定结构的连续位域成员应打包到同一“单元”中,如果该单元中仍有足够的空间。

来自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.

因此,在您的第一个结构中,前三个字段可以打包到一个 8 位单元中,但是第四个字段必须放置在一个单独的 32 位单元中(这将可能需要 4 字节对齐,从而将结构的整体大小增加到 8 字节)。 在这种情况下也可能很重要的是,填充字节将被添加到结构中,如果您的代码依赖于连续位,这可能会导致问题。

但是,在第二种情况下,所有四个位字段都可以放置在一个单个 32 位单元中,因此结构大小可以减少到仅 4 个字节。

但请注意,这可能因编译器和平台而异 - 特别是,如 Compiler Explorer example linked in the comments 中所示。 ,实现有权为第一个结构的前三个成员分配 32 位单元。

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

#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 - C 结构体中的位域表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73162600/

相关文章:

C:如何正确访问通过引用传递的结构体的数组元素?

c - C 中的反转位并将二进制转换为十进制

python - 调试 Python C 扩展模块中的引用计数内存泄漏

c - 非常大的结构并出现段错误

c++ - 在 C++ 中分配可变大小缓冲区的 "proper"方法是什么?

c++ - 使用正确的结构将 BMP 读入内存

c - 改进 32 位机器上结构的内存对齐

c - 我在运行程序时遇到段错误(核心转储)

c - 如何在 C 中读取一行中的多个单词?

c - malloc 无法为队列中的结构创建空间