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

一、没有成员的结构体占用的空间是多少个字节?

答案是:1个字节。

这就是实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类或空结构体(C++中结构体也可看为类)隐含的加一个字节,这样空类或空结构体在实例化后在内存得到了独一无二的地址,所以空类所占的内存大小是1个字节。

二、首先介绍一个相关的概念——偏移量

struct stru 
         {  
                    int a;  //start address is 0
                   char b;  //start address is 4
                   int c;  //start address is 8
         };

偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量的首地址。比如上面的结构体,第一个成员a的偏移量为0。第二个成员b的偏移量是第一个成员的偏移量加上第一个成员的大小(0+4),其值为4;第三个成员c的偏移量是第二个成员的偏移量应该是加上第二个成员的大小(4+1)。

三、在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:

(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)

(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。

例子1:
struct stru1  
{  
     int a;  //start address is 0
     char b;  //start address is 4
     int c;  //start address is 8
};

PS:用sizeof求该结构体的大小,发现值为12。int占4个字节,char占1个字节,结果应该是9个字节才对啊,为什么呢?这个例子中前两个成员的偏移量都满足要求,但第三个成员的偏移量为5,并不是自身(int)大小的整数倍。编译器在处理时会在第二个成员后面补上3个空字节,使得第三个成员的偏移量变成8。结构体大小等于最后一个成员的偏移量加上其大小,上面的例子中计算出来的大小为12,满足要求。

例子2:

struct stru2  
{  
      int i;  //start address is 0
      short m;  //start address is 4
};

PS:成员i的偏移量为0;成员m的偏移量为4,都不需要调整。但计算出来的大小为6,显然不是成员m大小的整数倍。因此,编译器会在成员m后面补上2个字节,使得结构体的大小变成8从而满足第二个要求。

例子3、4:

struct stru3  
{   
       char i;  //start address is 0 
       int m;   //start address is 4
       char n;  //start address is 8
};  
struct stru4  
{  
       char i;  //start address is 0
       char n;  //start address is 1
       int m;  //start address is 4
 };

虽然结构体stru3和stru4中成员都一样,但sizeof(struct stru3)的值为12而sizeof(struct stru4)的值为8。

由此可见,结构体类型需要考虑到字节对齐的情况,不同的顺序会影响结构体的大小。

四、对于嵌套的结构体,需要将其展开。对结构体求sizeof时,上述两种原则变为:
       (1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。

(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。

例子1:

struct stru5  
{  
      short i;  
      struct   
      {  
           char c;  
           int j;  
      } tt;   
      int k;  
};

结构体stru5的成员tt.c的偏移量应该是4,而不是2。整个结构体大小应该是16。

例子2:

struct stru6  
{  
      char i;  
      struct   
      {  
           char c;  
           int j;  
      } tt;   
      char a;  
      char b;  
      char d;  
      char e;  
      int f;  
};

结构体tt单独计算占用空间为8,而stru6的sizeof则是20,不是8的整数倍,这说明在计算sizeof(stru6)时,将嵌套的结构体ss展开了,这样stu6中最大的成员为tt.j,占用4个字节,20为4的整数倍。如果将tt当做一个整体,结果应该是24了。

五:另一个特殊的例子是结构体中包含数组,其sizeof应当和处理嵌套结构体一样,将其展开,如下例子:

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

其值为20。float占4个字节,到char p时偏移量为4,p占一个字节,到int arr[3]时偏移量为5,扩展为int的整数倍,而非int arr[3]的整数倍,这样偏移量变为8,而不是12。结果是8+12=20,是最大成员float或int的大小的整数倍。

测试环境:vc++6.0

测试代码:

//#ifndef __cplusplus

//#endif

#include <iostream>
#include "stdio.h"
#include <stdlib.h>
using namespace std;

struct stru_empty
{

};
struct stru1
{
int a; //start address is 0
char b; //start address is 4
int c; //start address is 8
};
struct stru2
{
int i; //start address is 0
short m; //start address is 4
};
struct stru3
{
char i; //start address is 0
int m; //start address is 4
char n; //start address is 8
};
struct stru4
{
char i; //start address is 0
char n; //start address is 1
int m; //start address is 4
};

struct stru5
{
short i;
struct
{
char c;
int j;
} ss;
int k;
};
struct stru6
{
char i;
struct
{
char c;
int j;
} tt;
char a;
char b;
char d;
char e;
int f;
};
struct stru7
{
char i;
struct
{
char c;
//int j;
} tt;
char a;
char b;
char d;
char e;
int f;
};
struct array
{
float f;
char p;
int arr[3];
};
int main()
{
struct stru6 st6;
struct stru7 st7;
struct array ar;
printf("sizof(char)=%d \n",sizeof(char));
printf("sizof(int)=%d \n",sizeof(int));
printf("sizof(short int)=%d \n",sizeof(short int));
printf("sizof(long int)=%d \n",sizeof(long int));
printf("sizof(long)=%d \n",sizeof(long));
printf("sizof(float)=%d \n\n",sizeof(float));

printf("sizof(stru_empty)=%d \n",sizeof(stru_empty));
printf("sizof(stru1)=%d \n\n",sizeof(stru1));
printf("sizof(stru2)=%d \n\n",sizeof(stru2));
printf("sizof(stru3)=%d \n\n",sizeof(stru3));
printf("sizof(stru4)=%d \n\n",sizeof(stru4));
printf("sizof(stru5)=%d \n\n",sizeof(stru5));
printf("sizof(stru6)=%d \n",sizeof(stru6));
printf("sizof(stru6.tt)=%d \n",sizeof(st6.tt));
printf("the address of stru6.i=%d \n",&st6.i);
printf("the address of stru6.a=%d \n\n",&st6.a);

printf("sizof(stru7)=%d \n",sizeof(stru7));
printf("sizof(stru7)=%d \n",sizeof(st7.tt));
printf("the address of stru7.i=%d \n",&st7.i);
printf("the address of stru7.a=%d \n\n",&st7.a);

printf("sizof(ar)=%d \n",sizeof(ar));
printf("sizof(ar.f)=%d \n",sizeof(ar.f));
printf("sizof(ar.arr)=%d \n",sizeof(ar.arr));
return 0;
}
运行结果:

————————————————
版权声明:本文为CSDN博主「海月汐辰」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37858386/article/details/75909852

sizeof()计算结构体的大小的更多相关文章

  1. sizeof操作符-结构体与类大小

    导读 sizeof是C/C++一个难点,当在自定义类上应用sizeof操作符时,总会出现意想不到的结果,下面,我们就来探讨一下sizeof这个操作符! 目录 1. sizeof与strlen的区别 2 ...

  2. C-sizeof和strlen区别,以及sizeof如何计算结构体大小

    sizeof和strlen区别 sizeof是关键字,在编译时就能计算出值,可以计算任何类型 strlen是函数,只有在运行时才能去计算,且只能计算字符型的. 对于数组时,strlen是判断’\0’为 ...

  3. 关于结构体占用空间大小总结(#pragma pack的使用)

    关于C/C++中结构体变量占用内存大小的问题,之前一直以为把这个问题搞清楚了,今天看到一道题,发现之前的想法完全是错误的.这道题是这样的: 在32位机器上,下面的代码中 class A { publi ...

  4. 【2017-07-01】Linux应用开发工程师面试问题记录之二:关于结构体的大小及内存对齐问题

    Tencent后台服务器开发有一道题是计算一个结构体的sizeof的大小: struct strData { int m_Int; char m_Char; short m_Short; char m ...

  5. sizeof(结构体) = ?

    关于结构体大小怎样计算的文章,我想网上一搜到处都有人总结,本人之所以在此基础上还要发表这样的文章是想用最简单的计算方法来总结前人给出的结论,以致我们在以后在对结构体相关编程中不会陷入字节对齐的陷阱中. ...

  6. 结构体(struct)大小

    结构体(struct)大小 本文参考链接:C语言结构体(struct)常见使用方法,链接中的实例代码经实践有几处不准确,本文在引用时已做更改 注意:在结构体定义时不能申请空间(除非是结构体变量),不可 ...

  7. YTU 2577: 小数计算——结构体

    2577: 小数计算--结构体 时间限制: 1 Sec  内存限制: 128 MB 提交: 978  解决: 647 题目描述 小数可以看成是一个点和两个数组成的,因此可以定义成一个小数的结构体,现在 ...

  8. sizeof求结构体大小

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...

  9. 计算结构体、数组、指针的sizeof

    1. 结构体的sizeof 题目: sturct aa{ in num; char name[10];}; struct bb{ int a; float b; struct aa c;}; stru ...

随机推荐

  1. Java生鲜电商平台-销售管理设计与架构

    Java生鲜电商平台-销售管理设计与架构 说明:在Java开源生鲜电商平台中,销售人员我们称为跟餐饮店老板沟通与下载APP的一类地推人员.(所谓地推指的就是一个一个上门拜访.) 由于销售人员有以下几类 ...

  2. day 34 作业

    作业 mysql> create table tea( -> id int unsigned auto_increment primary key, -> name varchar( ...

  3. CentOS7 配置 SSH监听多个端口方法

    一.修改ssh默认端口,防止暴力破解,让系统安全多一点点: i. 在配置文件/etc/ssh/sshd_config文件中修改 Port #AddressFamily any #ListenAddre ...

  4. Python从零开始——函数

    一:Python函数知识概览 二:函数的定义与调用 三:参数传递 四:函数返回值 五:匿名函数的定义与调用 六:变量作用域与改变变量作用域

  5. 使用map将字数组里的对象重新组装

    变为数组  ["扬子","北京","上海海吉雅"] // 注意点 map循环的时候 不能够有空的 否则回出问题哦. var list= [{ ...

  6. 【BZOJ3716】[PA2014]Muzeum(贪心+网络流)

    BZOJ 题意: 在二维网格图中有\(n\)个物品,每个物品有价值:但有\(m\)个警卫看管这些物品,每个警卫面朝\(y\)轴负方向,能看到一定角度(假定能够看到无穷远). 现在每个敬畏有一个贿赂价钱 ...

  7. 201871010102-常龙龙《面向对象程序设计(java)》第十周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  8. 怎么写Java项目?

    我们通常说的Java项目也都是JavaWeb,J2ee项目;现在说的是JavaWeb. 最简单的办法 多看别人项目源码 在别人基础上修改,而现在要一点一点掰开看看. 1.立项: 要做什么东西,最后的要 ...

  9. 配置好运行后Error creating context 'spring.root': Could not load type from string value

    在Webconfig文件的当前项目下引用相关项目

  10. pyenv python 多版本管理工具

    pyenv fork 自rbenv 以及ruby-build ,然后修改为转为python 使用 venv 以及virtualenv 解决了版本选择的问题,pyenv 同时为我们解决 了python ...