C-类型名称:数字?

C-类型名称:数字?,c,memory-management,C,Memory Management,我想知道下面的代码到底在做什么?我知道这与内存对齐有关,但当我询问sizeof(vehicle)时,它会打印20,但结构的实际大小是22。我只是想知道这是怎么回事,谢谢 struct vehicle { short wheels:8; short fuelTank : 6; short weight; char license[16]; }; printf("\n%d", sizeof(struct vehicle)); 20 内存将分配为(

我想知道下面的代码到底在做什么?我知道这与内存对齐有关,但当我询问sizeof(vehicle)时,它会打印20,但结构的实际大小是22。我只是想知道这是怎么回事,谢谢

  struct vehicle {
    short wheels:8;
    short fuelTank : 6;
    short weight;
    char license[16];
  };

  printf("\n%d", sizeof(struct vehicle));

  20

内存将分配为(假设内存字大小为
8
位)


1+1+2+16=20
字节。

考虑字长为32位的机器。前两个字段占用
8+6=14
位,因此适合于整个16位字。第二个字段虽然不是位字段(没有以位分配空间的
功能),但可以容纳另一个16位字来完成一个32位字,因此如果体系结构允许以16位数量访问内存,那么前三个字段可以打包成一个32位字(4字节)。最后,如果您在其中添加16个字符,这将给出
sizeof
操作符发送给printf的20个字节

为什么假定(结构车辆)的大小为22字节?你让编译器打印出来,它说是20。编译器可以自由填充(或不填充)结构以获得更好的性能。这是一个体系结构依赖项,正如您没有提到的体系结构和编译器的使用,不可能再进一步了

例如,32位intel arch允许在偶数边界上填充字,而不会影响性能,因此这是一个节省内存的好选择。在其他架构上,可能不允许使用16位整数,并且必须填充数据以适合第三个字段(导致整个结构有22个字节)

在调整数据大小时,您唯一的保证是编译器必须分配足够的空间以有效的方式容纳所有内容,因此您可以从该声明中假设的唯一一点是,它将至少占用最小空间来表示一个8位字段,另一个6位字段,一个完整的短字段(我假设短字段是16位)和16个字符(假设每个字符8位)的最小值为
8+6+16+16*8=158位

假设我们正在为D.Knuth混合机编写一个编译器。正如他在《基本算法》一书中所述,这台机器的未指定字节大小为64..100字节,需要5个字节来构造一个可寻址字(加上一个二进制符号)。如果您有一个与字节大小无关的编译器(一个为任何混合机编译的编译器,不需要假设字节大小),那么每个字节使用的可能值不超过64个,从而导致每个字节6位。然后,假设第二个字段填充一个完整字节(以及从它所属的单词中提取的符号),第一个字段需要两个完整字节(使用负值值的一半)。第三个字段可能位于第二个单词中,填充三个完整字节(
6*3=18
)和该单词的符号。接下来的16个字符可以从下一个单词开始,总计为5个完整单词,因此整个结构将包含
1+1+4=6
单词,或30个字节。但是,如果您想有效地处理三个带符号的字段,那么这三个字段需要三个完整的字(因为每个字段只有一个符号字段),这将导致7个字或35个字节

我之所以提出这个例子,是因为这种体系结构的特殊性,这让我们想到了一些不太常见的体系结构,这些体系结构在不久前是常用的(有史以来第一台不是基于二进制的机器,比如一些混合机)

注 您可以尝试打印字段的实际偏移量,以查看结构中的位置以及编译器填充的位置

#define OFFSET(Typ, field) ((int)&((Typ *)0)->field)
(注,已编辑)

此宏将以
int
的形式告诉您偏移量。将其用作偏移量(结构车辆,重量)
或偏移量(结构车辆,许可证[3])

注 我不得不编辑上一个宏定义,因为它在某些体系结构上抱怨指针->int的转换并不总是可能的(在64位体系结构上,它会丢失一些位),所以最好计算两个指针的差,这是一个合适的
大小\u t
值,而不是直接从指针转换

#define OFFSET(Typ, field) ((char *)&((Typ *)0)->field - (char *)0)

但是如何填充2位呢?@user3373360;根据。好的,如果我在轮子后面把:8改成a:6,那到底是什么变化,会有什么不同?我只是不明白“8”的值和“6”的值有什么不同?8代表什么?对于
大小\u t
参数,格式化
%d
也是错误的。它可能只在32位机器上工作。改为使用
%zu
size\u t
是无符号类型(因此
u
),并且
z
确保使用正确的宽度。使用
%zu\n“
,而不是
”\n%d“
<代码>\n标记行尾。
#define OFFSET(Typ, field) ((char *)&((Typ *)0)->field - (char *)0)