C 结构和相应变量的大小

C 结构和相应变量的大小,c,C,如果我定义一个char变量 char a; 和具有单个char成员的结构 struct OneChar { char a; }; 在所有编译器中,这两个定义的大小是否都与“char”相同? 我的疑问是,如果我们在结构中定义一个char变量,由于内存压缩,它需要的大小会大于char的大小吗?只要有一个成员,我认为您可以放心地假设。这取决于体系结构和编译器。对于这种特殊情况,您应该是安全的,但请检查 这是一个: x86上C结构的典型对齐方式 存储数据结构成员 按顺序存储在内存中,以便 成员数据1

如果我定义一个char变量

char a;
和具有单个char成员的结构

struct OneChar {
char a;
};
在所有编译器中,这两个定义的大小是否都与“char”相同?
我的疑问是,如果我们在结构中定义一个char变量,由于内存压缩,它需要的大小会大于char的大小吗?

只要有一个成员,我认为您可以放心地假设。

这取决于体系结构和编译器。对于这种特殊情况,您应该是安全的,但请检查

这是一个:

x86上C结构的典型对齐方式

存储数据结构成员 按顺序存储在内存中,以便 成员数据1下面的结构 将始终位于Data2和Data2之前 将始终位于数据3之前:

struct MyData
{
    short Data1;
    short Data2;
    short Data3;
};
如果类型“short”存储在两个 字节的内存,然后是 上面描述的数据结构 将是2字节对齐的。数据1将 位于偏移量0处,数据2位于偏移量2处,并且 偏移量4处的数据3。这个大小 结构将是6个字节

系统中每个成员的类型 结构通常有一个默认值 对齐,意味着它将, 除非业主另有要求 编程器,在一条直线上对齐 预先确定的边界。以下 典型路线适用于以下情况: 来自Microsoft、Borland和 为32位x86编译时的GNU:

  • 字符(一个字节)将按1字节对齐
  • 短的(两个字节)将是2字节对齐的
  • int(四个字节)将是4字节对齐的
  • 浮点(四个字节)将是4字节对齐的
  • 双字节(8字节)在Windows上是8字节对齐的,在Linux上是4字节对齐的
这是一个包含 各种类型,之前总共8个字节 汇编:

struct MixedData
{
    char Data1;
    short Data2;
    int Data3;
    char Data4;
};
在编译数据结构之后 将添加填充物 字节,以确保正确对齐 各成员:

struct MixedData  /* after compilation */
{
    char Data1;
    char Padding0[1]; /* For the following 'short' to be aligned on a 2 byte boundary */
    short Data2;
    int Data3;  
    char Data4;
    char Padding1[3];
};
结构的编译大小为 现在是12字节。注意这一点很重要 最后一个成员用 所需的字节数 符合最大类型的 结构。在这种情况下,需要3个字节 添加到最后一个成员以填充 一个长单词大小的结构

可以更改对齐方式 减少内存的结构 他们要求(或遵守)一个 通过更改 编译器的对齐(或“打包”) 结构件

请求混合数据 上面的结构必须与一个对齐 字节边界将包含编译器 放弃预先确定的对齐方式 的成员,并且没有填充字节 将插入

虽然没有标准的方法 定义结构的对齐方式 各位成员,有些编译器使用#pragma 用于指定内部包装的指令 源文件。以下是一个例子:

#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1)     /* set alignment to 1 byte boundary */

struct MyPackedData
{
    char Data1;
    long Data2;
    char Data3;
};

#pragma pack(pop)   /* restore original alignment from stack */
此结构将具有一个已编译的 大小为6字节。上述指示 在编译器中可以从 微软、Borland、GNU和许多 其他的


所有
a
s将具有相同的大小,无论它们是独立的还是在结构内部


结构内部可能发生的情况是,成员之间存在填充。。。但这种情况也可能发生在“独立”变量中。

当您计算结构的大小时,它包括填充字节。但是,如果您有以下情况:

void fun()
{
    char c;
    int n;
}

编译器可以出于任何原因自由插入填充。因此,在独立变量的情况下,填充可能在那里,你只是不知道这一点,就像在结构的情况下一样。

你列出的情况将在我知道的所有ABI下打包为一个1字节的结构

但如果您需要可移植地处理更复杂的情况,最佳做法是在计算内存大小时始终使用
sizeof(struct OneChar)
,并在需要通过以下技巧计算地址时使用字段地址的偏移量:

(char*)&(((struct OneChar*)0)->a) - (char*)0

各种编译器将优化以在结构之间或结构末尾添加填充。因此,在所有的编译器或平台上,假设分配的大小是看起来的大小是不安全的。检查编译器选项以设置结构填充


例如,Visual Studio使用该指令覆盖默认优化。

我认为结构中的第一个字段必须位于偏移量0处。另外,在
中有
offset of
,它将执行可怕的空指针技巧,因此您不必这样做。我真正的疑问是,在单成员结构中,内存填充是否会起作用?在您的情况下,我不这么认为,但正如我之前所说的,这取决于。我真正的疑问是,在单成员结构中,内存填充会起作用吗?还允许在最后一个成员之后进行填充(不仅仅是在成员之间)。