sizeof必须要知道的那些事

本文探讨了sizeof操作符在计算自定义类型时涉及的内存对齐问题,通过实例分析了不同环境下结构体的sizeof结果。介绍了VS与Linux环境下可能出现的差异,并详细解释了编译器的对齐规则,包括默认对齐方式和#pragma pack(n)的影响。通过对多个结构体的分析,阐述了如何计算结构体的大小,并提供了复杂数据结构对齐的处理提示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sizeof对于大多数人来说是即熟悉由陌生的。熟悉是指大家基本都用过,也知道sizeof是操作符不是函数;陌生就是指sizeof在计算自定义类型的时候,会涉及内存对齐方式,返回结果往往与我们想的大相径庭。本文就是结合内存对齐方式来介绍如何求sizeof的返回值。先来做个测试,各位看官如能准确说出下面几个结构体的sizeof大小的话,楼主觉得你已经没有必要再看下去,请出门左拐~ 

struct st1
{
	double a;
	char b;
	int c;
};
struct st2
{
    char b;
    double a;
    int c;
};

#pragma pack(push)  
#pragma pack(4) 
struct st3 
{ 
char b; 
double a; 
int c; 
}; 
#pragma pack(pop)

#pragma pack(8)
struct inst{
 char d;
 long e;
};

struct S2 {
 char a;
 struct inst b;
 long long c;
};
#pragma pack()

 

以上四个结构体sizeof的返回值,在VS上运行的结果和在Linux运行的结果会有所差异,个人觉得是g++做了优化。以下的讨论全是基于在VS上运行的结果,结果与Linux有差异的地方会特别指出。下面开始进入正题。

理论来说变量的内存地址可以是任意位置,但为了提高CPU的效率,减少读周期,编译器会对变量的地址进行对齐,默认情况下,VS的对齐方式要求满足以下两点:

1.各成员变量的起始地址相对于结构体起始地址的偏移量必须是该变量类型所占字节大小的倍数。各成员变量根据在结构体出现的次序申请空间,按照以上所说方式对齐调整位置,空字节由VS自动补齐。

2.确保结构体大小为结构体字节边界数的倍数,结构体字节边界数是指结构体中占用空间最大的类型的字节个数。

下面给出常见类型的大小和偏量:

类型            对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)

char              偏移量必须为sizeof(char)即1的倍数

int                 偏移量必须为sizeof(int)即4的倍数

float              偏移量必须为sizeof(float)即4的倍数

double            偏移量必须为sizeof(double)即8的倍数


Short             偏移量必须为sizeof(short)即2的倍数

讲到这,我们可以正确的求出前两个结构体的大小了,首先是st1,假设结构体起始地址为0,a占8字节,0是8的倍数,所以a放在地址0处,占8个字节。那么下一个地址为9,9是1的倍数(char b),所以b放在地址9处,占字节为1。因为c是4个字节,所以偏移量要为4的倍数,9开始最近的4的倍数为12,所以中间补齐3个字节,而c本身占4个字节。所以st1的大小为8+1+3(补)+4=16。16正好是st1字节边界数的倍数,所以最后不用再补齐,即st1的大小为16。

各位看官自行分析st2吧,st2的sizeof大小在VS下的运行结果是24,之所以不是20,因为要满足要求2。此外,st2在Linux下运行的结果是16,为什么是16,个人觉得跟编译器默认的 #pragma pack(n) 有关。g++应该是默认4字节对齐。下面我就开始讲一下在 #pragma pack(n)限制下的sizeof如何求。

 #pragma pack(n)是设置编译器默认对齐方式的指令,具体用法可以自行百度。一旦程序规定了 #pragma pack(n),对齐的方式要满足以下要求:

1.如果n大于等于变量类型所占用的字节数,则采用默认对齐方式。

2.如果n小于变量类型所占用的字节数,则偏移量满足是n的倍数即可,无需是变量类型所占字节的倍数。

3.结构体总大小的约束条件:如果n大于等于成员变量中最大的变量类型所占字节数,采用默认方式(即使边界字节数的倍数),否则为n的倍数即可。

现在我们来分析一下st3,首先是4字节对齐,继续假设结构体的起始地址为0,b因为(1<4)采用默认对齐方式,0是1的倍数,所以b的起始地址是0,接下来看a(8>4),此时不再是默认对齐方式,而是4字节对齐方式,所以a的起始地址是4,不是之前的8。此时偏移量是12,是4的倍数,所以c刚好可以。到此结构的大小是1+3(补)+8 + 4=16;

结构总大小满足是4的倍数(注意不是8)。所以最终结果是16。st3的运行结果在VS和Linux下一致。

对于最后一个结构体st4,大家可以自行去验证,而当结构体里面出现复杂数据结构(如结构体)时,它的偏移量按照复杂数据结构中最大的类型所占字节数来对齐,即inst的偏移量是4的倍数(long类型占4个字节)。而他本身是8字节。对于有复杂数据结构的求法给出以下三点提示:

1.每个成员分别按自己的方式对齐,并能最小化长度。

2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。

3.对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值