gpt4 book ai didi

c - 枚举和无符号长位域

转载 作者:行者123 更新时间:2023-12-02 03:02:59 25 4
gpt4 key购买 nike

如果我有以下带有枚举和 unsigned long 的结构,填充是如何完成的?我相信编译器不会对 var1var2 做任何事情,因为它是 32 位且已填充。

typedef struct {
unsigned long var1 : 8;
unsigned long var2 : 24;
my_enum var3 : 2;
my_enum var4 : 2;
} my_struct;

var3var4 是否都需要填充?例如 30 位填充到 var3 和 30 位到 var4,或 28 位。我只是想了解位域如何跨不同的数据类型和实现类型工作。

最佳答案

<强>1。位域中使用的类型:

我只会在您的结构中使用 signed intunsigned int 作为位域类型。根据C99 standard (6.7.2.1 #4):

A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type.

当然 unsigned longenum type 是实现定义的类型,但如果您使用它们,则行为不可移植。您可以在 2 个不同的 GCC 版本中看到它:

根据 gcc 4.8.4 的手册:

  • Allowable bit-field types other than _Bool, signed int, and unsigned int (C99 6.7.2.1).

No other types are permitted in strictly conforming mode.

根据 gcc-5.2.0 的手册:

  • Allowable bit-field types other than _Bool, signed int, and unsigned int (C99 and C11 6.7.2.1).

Other integer types, such as long int, and enumerated types are permitted even in strictly conforming mode.

<强>2。填充:

位域在字和字节级别工作,不能跨越字边界。 C99 保证位域将尽可能紧密地打包,前提是它们不跨越存储单元边界(6.7.2.1 #10)。

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.

如果您想将一个单元中现有的位字段填充到下一个单元中,您可以使用标准 (6.7.2.1 #11) 中所述的长度为零的位字段来实现:

As a special case, a bit-field structure member with a width of 0 indicates that no further bit-field is to be packed into the unit in which the previous bit- field, if any, was placed.

此外,它还说明了 C99 中的结尾(6.7.2.1 #15):

There may be unnamed padding at the end of a structure or union.


这对您的结构意味着什么:

您的var1var2 将一起存储在4 字节(32 位)的内存中,没有任何间隙。因为位域可以在字节级操作,所以您的 var3var4 也可以存储在一起代表一个字节。但是它们的顺序是实现定义的。如果您在它们之间放置一个零长度的位字段,var4 将从下一个对齐的单元开始。您的结构的末尾可能会被填充到 32 位或 64 位。


您的结构的真实代码示例:

因为你不能获取位域的地址,所以分析位域的行为并不是那么容易,这里是我编写的一小段代码,无论如何都要用一些变通方法来分析它。

我使用易于识别的位模式设置结构内的值,并打印出整个结构的每一位(使用 sizeof() 的总大小)。你可以看到 result on ideone , 或以下。请注意,所使用的系统对每个结构变量使用小端格式,因此与人类可读形式(大端格式)相比,字节被交换。此外,var3var4 的顺序不同,因为标准表示它是实现定义的。

输出:

sizeof(my_struct)     = 8
sizeof(my_struct_var) = 8
Byte 0: 1 0 0 0 0 0 0 1
Byte 1: 0 0 0 0 0 0 0 1
Byte 2: 0 0 0 0 0 0 0 0
Byte 3: 1 0 0 0 0 0 0 0
Byte 4: 0 0 0 0 1 1 1 0
Byte 5: 0 0 0 0 0 0 0 0
Byte 6: 0 0 0 0 0 0 0 0
Byte 7: 0 0 0 0 0 0 0 0

您的结构有效地使用了字节 0 到 3 和字节 4 的一半。因为我是在 64 位机器和 ideone 上编译的,半字节 4 被填充到字节 7。我还建议阅读这个 guideline about structure padding and bitfields .

代码:

#include <stdio.h>
#include <limits.h>

#if CHAR_BIT != 8
#error "unsupported char size"
#endif

typedef enum { ONE, TWO, THREE } my_enum;

typedef struct
{
unsigned long var1 : 8;
unsigned long var2 : 24;
my_enum var3 : 2;
my_enum var4 : 2;
} my_struct;

int main(void)
{
int idx;
int bitIdx;
my_struct my_struct_var;

memset (&my_struct_var,
0,
sizeof(my_struct_var));

printf("sizeof(my_struct) = %lu\n", sizeof(my_struct));
printf("sizeof(my_struct_var) = %lu\n", sizeof(my_struct_var));

my_struct_var.var1 = 0x81; /* 1000 0001 */
my_struct_var.var2 = 0x800001; /* 1000 0000 0000 0000 0000 0001 */
my_struct_var.var3 = 0b10; /* 10 */
my_struct_var.var4 = 0b11; /* 11 */

for (idx = 0; idx < sizeof(my_struct_var); ++idx)
{
char * curByte = &my_struct_var;
curByte += idx;
printf("\nByte %d: ", idx);
for (bitIdx = 0; bitIdx < CHAR_BIT; ++bitIdx)
{
printf("%c ", ((*curByte & (1 << ((CHAR_BIT - 1) - bitIdx))) >> ((CHAR_BIT - 1) - bitIdx)) + '0');
}
}

return 0;
}

关于c - 枚举和无符号长位域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44712923/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com