结构体大小计算(全网原创)

之前我就对结构体大小的计算总结过,但是没有记录下自己的总结,时间长了就会忘记,这次又遇到了需要计算结构体大小,那没办法,就当复习。CSDN的风气一直不好,基本TMD都是抄袭,你抄我,我抄你。离国外的差距远着,别的不说了,直接上干货

计算结构体的步骤我总结如下:

首先明白自己用的是什么开发环境,举个例子,如果你用的是VS,那么VS里的默认字节对齐数是8,这个8是怎么来的,很容易验证:

struct S
{
	int a;
	double b;
	short c;
	char d;
};

你试着计算下这个结构体的大小,对就直接考过去,咔的一下程序跑起来,结果是不是24。如果是就对了,接着你在main函数前面多加一条语句,记住别往函数里头加,就加在main函数前面就行,知道吧,加这条语句:

#pragma pack(4)

接着你继续咔的程序跑起来,这时候算的大小结果是不是16,OK验证结束
好了默认字节对齐数验证完,多加的这条语句的作用就是改变你默认的对齐字节数大小,括号里的4就是改变后的对齐大小,对就这么暴力,是不是很简单,别急。好,如果你用的是Linux 下的gcc编译器,那这时候就没有默认的字节对齐数,记住我说的,不服来辩,没有就是没有,gcc官方讲的,就是这么霸气,至于网上说的gcc默认对齐字节大小为4,确实可以反推出来为4,但是官方说没有,啊,记住了,没有就是没有

  1. 好了搞清楚你使用的开发环境后,接下来就是计算了,先讲VS环境下的计算吧,VS下的结构体大小计算:
struct S
{
	int a;
	double b;
	short c;
	char d;
};

简单的搞起,注意算结构体大小要学会自己动手画图
在这里插入图片描述

看上面的图,19字节肯定不是正确的,我只是为了抛转引玉,首先结构体中的每个成员,在内存中的布局是什么样的,为什么会有空着的内存,因为你在确定结构体成员对齐的时候你是要根据这个成员的数据类型大小和默认对齐字节数的大小进行对齐,而且是取这二者中较小的那个进行对齐,具体:
第一个成员是int 类型的变量,大小是4字节,而我们之前说的默认对齐字节数是8,取二者较小的那个对齐,那么就是取4对齐,并且,并且你的第一个成员的偏移量相对于自己是为0的,那也就是说第一个成员的起始位置可以是任意的,可以这么说吧,前提是这块内存空间是可用的,接着,第二个成员是double类型,也取二者当中较小的那个,两个都是8,那就是8咯,好,按8的倍数进行对齐,是多少就按多少的倍数对齐,先确定每个成员的对齐数,再按这个对齐数的整数倍对齐就OK了,所有都是这么算的好吧。
由于第一个int 占了0-3四个字节,下一个偏移量为4,不是8的倍数,得浪费,浪费4字节,4-7四个字节浪费掉,图片中的空白处就是这么来的,好下一个偏移量为8,是8的倍数,好,这时候就把double填进去,占8字节,那也就是说8-15八个字节是第二个成员的存储位置,接着第三个成员类型short,大小是2字节,还是取二者较小值,2跟8,2小,下一个偏移量是16,巧了,是2的倍数,填呗,16-17两字节也被占了,还剩最后一个成员char类型,还是那句话,取二者较小的那个,任何数都是1的倍数吧,所以18也接着被占了,0-18总共19个字节,但是最后最关键的一步,我已经把所有的过程都分析一遍,而且把每个成员的字节对齐数都算了一遍,来,回忆下:
第一个成员对齐数,取二者较小的--------------------4
第二个成员对齐数,取二者较小的--------------------8
第三个成员对齐数,取二者较小的--------------------2
第四个成员对齐数,取二者较小的--------------------1

好了,这四个成员的对齐数都有了,最后一步,选出里面最大的那个数,那就8咯,19是8的倍数吗,不是,所以又得浪费一些字节,变成24,才是8的倍数,到此计算的全部过程完成,全CSDN最细,不接受反驳。如果默认对齐字节数改成4,结果是怎样的,小伙伴自己动手去画一画,看结果是不是一样的,答案肯定是不一样的,最后在提醒你一句,取二者较小的那个,哈哈哈哈哈。对于结构体中嵌套结构体或者数组的套路一样的,先计算那个嵌套的结构体大小,在确定这个嵌套的结构体在内存的布局是怎样的,这个嵌套的结构体布局也要根据它里面最大的字节对齐数进行确定。

下面附上如果把对齐字节数改成4的结构体成员布局图,15字节不是最后的结果。。。。。


讲完了VS,来讲讲gcc,由于Linux下没有默认字节对齐,所以你不需要取二者较小值,直接按成员的类型大小的整数倍对齐就行了,最后取的那个字节对起数那就是取最大成员类型的大小,得出最后的结构体大小,例子我就不举例了,写博客真TM费时间,特别的原创的,一字一字敲出来真的。。。。。。。就是看不惯CSDN的一些现象,自己写的以后忘了查查马上就捡起来了,别人的终究还是别人的,你得把别人的消化吸收后,归纳总结为自己的,这是很关键的一点,写东西要写的像样点,最后因为最近在研究ICMP协议,看到了这么一个结构体,大家试着去计算一下这么一个结构体,你放心,不管有多复杂,按我的步骤来一定不会错,结构体如下:

struct icmp
{
  uint8_t  icmp_type;   /* type of message, see below */
  uint8_t  icmp_code;   /* type sub code */
  uint16_t icmp_cksum;  /* ones complement checksum of struct */
  union
  {
    unsigned char ih_pptr;  /* ICMP_PARAMPROB */
    struct in_addr ih_gwaddr;   /* gateway address */
    struct ih_idseq     /* echo datagram */
    {
      uint16_t icd_id;
      uint16_t icd_seq;
    } ih_idseq;
    uint32_t ih_void;
 
 	/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
    struct ih_pmtu
    {
      uint16_t ipm_void;
      uint16_t ipm_nextmtu; 
    } ih_pmtu;
 
    struct ih_rtradv
    {
      uint8_t irt_num_addrs;
      uint8_t irt_wpa;
      uint16_t irt_lifetime;
    } ih_rtradv;
  } icmp_hun;
  union
  {
    struct
    {
      uint32_t its_otime;
      uint32_t its_rtime;
      uint32_t its_ttime;
    } id_ts;
    struct
    {
      struct ip idi_ip; 		 //这个结构体大小直接告诉你是20字节
    } id_ip;
    struct icmp_ra_addr id_radv;      //这个结构体类型在下面
    uint32_t   id_mask;
    uint8_t    id_data[1];
   }icmp_dun;
};
  
struct icmp_ra_addr
{ 
  uint32_t ira_addr;
  uint32_t ira_preference;
};
 
在这里插入代码片

这个结构体还算复杂了,不过算这个也不难,联合体的大小计算还更简单,按照由内到外的顺序计算,不难,不过这个结构体得在Linux下去计算,VS没有包含这个结构体类型的头文件,好了,想牛逼就玩Linux,不过还是得看你从事哪个方向的开发,不是说所有人都要会Linux,后面有时间还会写写,因为这东西太费时间了,时间很宝贵,好好珍惜吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值