使用sizeof()计算结构体大小

下面代码的输出结果是:

#include <iostream> 
using namespace std; 
#pragma pack(4) 
struct T{    
    char a;    
    short b;    
    char c; 
}; 
#pragma pack()
 
int main() 
{    
    cout << sizeof(T) << endl;    
    return 0; 
}

A. 4 B. 5 C. 8 D. 6

一、sizeof()计算结构体大小

结构体成员按照定义时的顺序依次存储在连续的内存空间,但是结构体的大小并不是简单的把所有成员大小相加,而是遵循一定的规则,需要考虑到系统在存储结构体变量时的地址对齐问题。

  1. 结构体变量中成员的偏移量必须是成员大小的整数倍 (0是任何数的整数倍)
  2. 结构体大小必须是所有成员大小的整数倍 (即所有成员大小的公倍数
  3. 结构体大小计算方式:最后一个成员的偏移量加上其大小

例1:

struct T{    
    char a;    
    short b;    
    char c; 
}; 

【分析】

​ 第一个成员char a的偏移量为0
​ 第二个成员short b的偏移量为前一个成员的偏移量+前一个成员的大小,即0 + 1 = 1,因1不是该成员大小2的整数倍,所以需要调整到2(最小倍数),所以第二个成员的偏移量为2
​ 第三个成员char c的偏移量为第二个成员的偏移量+第二成员的大小2 + 2 = 4, 4是其大小1的整数倍,所以第三个成员的偏移量为4

​ 所以该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即4 + 1 = 5,但5不是所有成员大小(1, 2, 1)的整数倍,所以需要补齐到6

注:偏移量可以理解为结构体成员相对于结构体的起始地址


例2:嵌套的结构体

struct T  
{  
      short a;  
      struct   
      {  
           char b;  
           int c;  
      } tmp;   
      int d;  
};

对于嵌套的结构体,应该将其展开,规则变化为:

  1. tmp结构体的第一个成员的偏移量(代表tmp结构体在整个结构体中的起始地址)应当是tmp结构中最大成员大小的整数倍;
  2. 其它成员的偏移量计算方法不变
  3. 结构体大小sizeof(T)必须是展开后所有成员大小的整数倍

【分析】

​ 第一个成员short a的偏移量为0
​ 第二个成员char b, 其偏移量本是前一个成员的偏移量+前一个成员的大小, 即0 + 2 = 2,但它又是tmp结构体的第一个成员,其偏移量应该是tmp结构体中最大成员int c大小4的整数倍, 所以应该调整到4;
​ 第三个成员int c,偏移量为4 + 1 = 5,调整到其自身大小整数倍8;
​ 第四个成员int d,偏移量为8 + 4 = 12,已经是自身大小整数倍,无需调整;

​ 所以该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即12 + 4 = 1616是展开后所有成员大小(2, 1, 4, 4)的整数倍,所以无需再调整。


例3:包含数组成员的结构体

struct T  
{  
    float f;  
    char p;  
    int arr[3];  
};

将数组看成一个结构体,其中所有成员均为该数组类型变量,同样展开计算。

【分析】

​ 第一个成员float f偏移量为0;
​ 第二个成员char p偏移量为0 + 4 = 4,是其大小1的整数倍,无需调整;
​ 第三个成员int arr[3]为数组,展开为三个int类型成员计算
​ …
​ 最后一个成员的偏移量为16

​ 所以该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即16 + 4 = 2020是展开后所有成员大小(4, 1, 4)的整数倍,所以无需再调整。

二、#pragma pack(n)

编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:

  • 如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式
  • 如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

结构的总大小也有个约束条件,分下面两种情况:

  • 如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;
  • 否则必须为n的倍数。

总结一下,就是两条判断原则:

  1. 每个成员的偏移量必须是x的倍数, x = min(n,该成员大小)

  2. 结构体的总大小必须是y的倍数, y = min(n,占用空间大的变量的字节数)

例:

#pragma pack(4) 
struct T{    
    char a;    
    short b;    
    char c; 
}; 
#pragma pack()

【分析】

n = 4;
​ 第一个成员char a,其偏移量为0(无论n的值和第一个成员的类型,第一个成员的偏移量总是0);
​ 第二个成员short b, 计算x = min(4, 2) = 2,其偏移量为第一个成员的偏移量+第一个成员的大小,即0 + 1 = 1,因为1不是x的倍数,所以偏移量调整为2
​ 第三个成员char c,计算x = min(4, 1) = 1的偏移量为第二个成员的偏移量+第二成员的大小,即2 + 2 = 4, 4x的整数倍,所以第三个成员的偏移量为4

​ 计算y = min(4, max(1, 2, 1)) = 2, 该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即4 + 1 = 5,但5不是y的整数倍,所以需要补齐到6

三、总结

  1. 计算每个成员的偏移量:第一个成员偏移量总是0;其它成员偏移量=前一个成员偏移量+前一个成员大小, 然后根据规则调整;
  2. 计算结构体大小 = 最后一个成员偏移量 + 最后一个成员大小;再根据规则调整。
  3. 标注#pragma pack(n)和不标注的规则不一样, 嵌套结构体(或者带数组成员的结构体)的规则也发生变化。
  • 21
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值