struct的大小和相应的变量
如果我定义一个char变量
char a;
以及具有单个char成员的结构
struct OneChar { char a; };
这两个定义在所有编译器中的大小都是’char’吗? 我的疑问是,如果我们在结构中定义一个char变量,由于内存打包它会比char的大小更大吗?
这取决于架构和编译器。 对于这种特殊情况,您应该是安全的,但请查看数据结构填充 。
这是一段摘录 :
x86上C结构的典型对齐方式
数据结构成员按顺序存储在内存中,因此在下面的结构中,成员Data1将始终位于Data2之前,而Data2将始终位于Data3之前:
struct MyData { short Data1; short Data2; short Data3; };
如果类型“short”存储在两个字节的存储器中,那么上面描述的数据结构的每个成员将是2字节对齐的。 Data1将位于偏移0,Data2位于偏移2处,Data3位于偏移4.此结构的大小为6个字节。
结构的每个成员的类型通常具有默认对齐,这意味着除非程序员另外请求,否则它将在预定边界上对齐。 在编译32位x86时,以下典型的对齐对Microsoft,Borland和GNU的编译器有效:
- char(一个字节)将是1字节对齐的。
- 短(两个字节)将是2字节对齐的。
- int(四个字节)将是4字节对齐的。
- 浮点数(四个字节)将是4字节对齐的。
- 双(八字节)将在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个字节添加到最后一个成员,以将结构填充为长字的大小。
通过更改编译器对结构成员的对齐(或“打包”),可以更改结构的对齐以减少它们所需的内存(或符合现有格式)。
请求上面的MixedData结构与一个字节边界对齐将使编译器丢弃成员的预定对齐,并且不插入填充字节。
虽然没有标准的方法来定义结构成员的对齐,但是一些编译器使用#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个字节。 上述指令可在Microsoft,Borland,GNU和许多其他编译器中获得。
只要有一个成员,我认为你的假设是安全的。
您列出的案例将在我知道的所有ABI下打包为1字节结构。
但是如果你需要可移植地处理更复杂的情况,最佳做法是在计算内存大小时始终使用sizeof(struct OneChar)
,并在需要通过以下方法计算地址时获取字段地址的偏移量:
(char*)&(((struct OneChar*)0)->a) - (char*)0
所有s都具有相同的大小,无论它们是独立的还是在结构内。
结构内部可能发生的是成员之间存在填充……但这也可能发生在“独立”变量中。
获取结构的大小时,它包含填充字节。 但是,如果您有类似以下内容:
void fun() { char c; int n; }
无论出于什么原因,编译器都可以自由插入填充。 因此,在独立变量的情况下,填充可能存在,你只是在结构的情况下无法知道。
各种编译器将优化以在结构之间或结尾处添加填充。 因此,在所有编译器或平台上假设分配的大小看起来并不安全。 检查编译器选项以设置struct padding。
例如,Visual Studio使用#pragma pack
指令覆盖默认优化。