我找到了如下结构的代码段:
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/