在C语言中,struct的大小
在C语言中,struct的大小
阅读完这个链接后,我还是不明白我这个结构体的大小是多少:
struct s { char c1[3]; long long k; char c2; char *pt; char c3; }
而`sizeof(struct s)`返回的是`40`。
但根据我提到的帖子,我认为内存应该是这样的:
0 1 2 3 4 5 6 7 8 9 a b c d e f +-------------+- -+---------------------------+- - - - - - - -+ | c1 | |k | | +-------------+- -+---------------------------+- - - - - - - -+ 10 11 12 13 14 15 16 17 +---+- -+- -+- - - - - -+----+ |c2 | |pt | | c3 | +---+- -+- -+- - - - - -+----+
所以我应该得到的是`18`而不是`40`...
有人能解释一下我哪里错了吗?非常感谢!
在C语言中,结构体的大小(Sizeof a struct in C)可能与对齐(alignment)有关。为了改变对齐方式,gcc提供了#pragma pack(push,n)
和#pragma pack(pop)
的指令。
如果要声明一个结构体,可以使用__attribute__((__packed__))
来改变对齐方式,例如:
struct packed { char c1[3]; long long k; char c2; char *pt; char c3; } __attribute__((__packed__));
在使用gcc编译时,sizeof(packed)
的结果为18,因为按照结构体中各个成员的大小计算:
c1: 3 k : 8 c2: 1 pt: 4 // 取决于指针的大小 c3: 1
值得注意的是,Visual C++编译器也支持#pragma pack(push,n)
这种方式。
以上就是改变结构体对齐方式的原因和解决方法。
在C语言中,结构体的大小取决于使用的编译器和启用的编译器选项。C语言标准对编译器创建结构体时如何利用内存没有作出任何承诺,即使使用同一编译器,不同的体系结构(例如32位WinTel vs 64位WinTel)也会导致不同的布局决策。
实质上,结构体的大小等于字段元素所需字节的大小之和(通常可以计算),加上编译器注入的填充字节的大小之和(通常不可知)。
这个问题的出现是因为不同编译器在创建结构体时对内存利用的方式不同。编译器可能会在结构体中插入额外的填充字节,以对齐内存访问,或者为了优化内存访问而对结构体进行重新排列。这些填充字节的大小和位置是由编译器决定的,往往无法预测。
要解决这个问题,可以采取以下几种方法:
1. 使用编译器提供的特定选项来控制结构体的对齐方式。例如,GCC编译器提供了`#pragma pack`指令,可以设置结构体的对齐方式。
2. 使用特定的编译器标志来禁用或启用特定的优化选项。例如,可以使用`-fno-strict-aliasing`标志来禁用严格别名规则,从而避免编译器对结构体进行优化。
3. 手动调整结构体的布局,以确保字段的对齐和填充满足特定的需求。这可以通过在结构体中插入额外的字段或使用特定的数据类型来实现。
总之,结构体大小的计算和填充字节的注入是由编译器决定的,并且可能因不同的编译器和编译器选项而有所不同。为了获得可移植性和一致性,我们应该避免对结构体的大小和布局做出假设,并尽量使用编译器提供的特定选项来控制结构体的对齐方式。
一个结构体的大小在C语言中是由硬件、编译器和平台的ABI(应用程序二进制接口)决定的。结构体中的成员需要按照特定的对齐要求进行分配,以确保结构体的数组和结构体的元素都能够正确对齐。
在上述例子中,假设指针大小为8字节,long long
类型和指针的对齐要求也是8字节。根据这些规则,结构体的大小可以计算如下:
- c1
需要3字节
- 5字节的填充
- k
需要8字节
- c2
需要1字节
- 7字节的填充
- pt
需要8字节
- c3
需要1字节
- 7字节的填充
所以结构体的大小为40字节。
结构体的尾部填充是为了保证结构体的数组能够正确对齐。值得注意的是,结构体的大小、对齐要求和填充取决于硬件、编译器和平台的ABI。在这里使用的规则是常见的规则:N字节大小的类型(N为{1, 2, 4, 8, 16}中的一个)需要按照N字节边界进行分配。结构体内部和结构体数组都需要正确对齐。可以使用#pragma
指令来调整填充大小,但要小心使用。通常最好将结构体的最严格对齐的成员放在开头,对齐要求较低的成员放在结尾。
如果使用以下结构体定义:
struct s2 { long long k; char *pt; char c1[3]; char c2; char c3; };
所需的大小将只有24字节,只有3字节的尾部填充。这说明结构体的成员顺序是有影响的。
尾部填充的目的是为了保证结构体的数组能够正确对齐。这样可以提高效率,使得下一个元素能够在下一个主要边界上对齐。