以下均是在VS2017下的结果

结构体内存大小的计算:

用例一:

#include<stdio.h>
union ss
{
int a;
char b;
};
struct MyStruct
{
int temp1;//4个字节
char temp2;//一个字节,补齐3个字节
ss aa;//4个字节
char temp3;//一个字节
char temp4;//一个字节,补齐两个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}

  输出 16

解析:对齐规则是按照成员的声明顺序,依次安排内存,对齐字节数为最大成员变量的字节大小,偏移量为最大成员变量的字节数的整数倍,在这个程序中对齐字节数为4,计算步骤如下:

首先是temp1 四个字节,temp2 一个字节,还剩3个字节,因为后面是aa 4个字节,可以自己对齐,所以temp2需要补齐3个字节, temp3 一个字节,temp4一个字节,对齐是4个字节,还剩2个字节需要补齐。所以总共是16个字节。

#include<stdio.h>
union ss
{
int a;
double b;
};
struct MyStruct
{
int temp1;//4个字节
char temp2;//1个字节,对齐是8个字节,还需3个字节补齐
ss aa;//8个字节
char temp3;//1个字节
short temp4;//2个字节,补齐还需要5个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}

  输出结果为 24

#include<stdio.h>
union ss
{
int a;
double b;
}; struct student
{
int name;
char sex;
double num; };
struct MyStruct
{
int temp1;//4个字节
char temp2;//1一个字节,补齐3个字节
ss aa;//8个字节
char temp3;//一个字节
short temp4;//2个字节,补齐5个字节
student people;//16个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}

  结果为 40

解析:此时需要注意的是,对齐字节数8个字节,而不是16个字节。student people 对象内部先进行一次对齐,然后如果如果是外面对齐字节数的整数倍就不需要

再进行对齐了,如果不是就需要再次进行对齐。

下面的是需要二次对齐的程序:

#include<stdio.h>
struct MyStruct
{
char temp1;
char temp2;
};
struct student
{
int name;//4个字节
char sex;//1个字节
MyStruct aa;//2个字节
char temp;//1个字节 };
int main()
{
printf("%d", sizeof(student)); }

  输出为 8

#include<stdio.h>
union ss
{
int a;
double b;
}; struct student
{
//int name;
//char sex;
int num; };
struct MyStruct
{
int temp1;//4个字节
char temp2;//1一个字节,补齐3个字节
ss aa;//8个字节
char temp3;//1个字节
short temp4;//2个字节
student people;//4个字节,补齐一个字节
};
int main()
{
printf("%d", sizeof(MyStruct));
return 0;
}

  输出结果为:24

总结,在一个结构体中有另一个结构体的对象时,对齐字节数与这个结构体对象的字节数无关,只与结构体中的成员变量和union 有关。

类的内存大小的计算

只含有成员函数的类和空类的内存大小:

#include<iostream>
using namespace std;
class student
{
public:
student()
{
cout << "构造函数" << endl;
}
//void fun();
};
int main()
{
cout << sizeof(student) << endl;
return 0;
}

  运行结果: 1

解析:如果是空类也会输出1。如果一个类只含有成员函数没有成员变量或者虚函数,类的大小都是1。如果含有静态成员变量或者是静态成员函数,也会是1,因为静态成员变量和静态成员函数是类的所有对象共享的,它并不存放在一个实例化对象中

为什么空类也会是1呢?

所谓类的实例化就是在内存中分配一块地址,每一个实例在内存中都有独一无二的地址,而了到达这个效果,编译器往往会给一个空类隐含的增加一个字节,这样实例化出来的每一个空类的对象都会得到一个独一无二的地址。如果空类的大小是0的话,那么实例化出来的所有空类对象都是在同样一个内存地址上,就相当于同一个对象,这不是我们想要的。

只含有静态成员函数和静态成员变量的类的内存大小:

#include<iostream>
using namespace std;
class student
{
static int b;
static void func();
};
int main()
{
cout << sizeof(student) << endl;
return 0;
}

  输出结果:1

解析:因为静态成员变量和静态成员函数都是类的所有对象共享的,静态成员变量存放在全局存储区,静态成员变量和静态成员函数在编译时就已经在全局区分配的内存。

含有成员变量的类的内存大小:

#include<iostream>
using namespace std;
class student
{
int a;//4个字节
char c;//1个字节,对齐,需要补齐3个字节
static int b;
static void func();
};
int main()
{
cout << sizeof(student) << endl;
return 0;
}

  输出为 8

含有虚函数的类的内存大小:

#include<iostream>
using namespace std;
class student
{
int a;//4个字节
char c;//1一个字节,对齐,补齐3个字节
static int b;
public:
static void func();
virtual void fly();//4个字节
};
int main()
{
cout << sizeof(student) << endl;
return 0;
}

  

  输出为 12

解析:虚函数会产生一个虚函数指针,指针大小为4个字节,虚函数指针指向虚函数表。

但是并不是每一个虚函数都会产生一个虚函数指针,同一个类中的所有虚函数只会产生一个虚函数指针。

继承下的类的内存大小:

#include<iostream>
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void fly();
};
class student1: public student
{
int d;//4个字节
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}

  输出 16

解析:派生类会继承父类的成员变量和虚函数等,所以子类的内存大小是在父类的内存大小的基础上加上自己增加的内存大小。

父类和子类中都有虚函数的类的内存大小:

#include<iostream>
using namespace std;
class student
{
int a;
char c;
static int b;
public:
static void func();
virtual void fly();
};
class student1: public student
{
int d;
public:
void fly();
virtual void eat();
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}

  输出为:16

问题:子类声明了一个虚函数且该虚函数是父类中没有的虚函数为什么子类没有新产生一个虚函数指针。

这个涉及到内存布局问题,首先是基类产生了一个虚函数指针,这个虚函数指针会指向虚函数表,表中存放的是基类的虚函数。子类也会继承到这个虚函数指针,虚函数指针指向虚函数表,表中先是存放基类的虚函数,再存放子类的基函数,如果子类重载了父类的某些虚函数,那么新的虚函数将虚函数表中父类对应的虚函数覆盖

虚继承——空类

#include<iostream>
using namespace std;
class student
{ };
class student1: virtual student
{ };
int main()
{
cout << sizeof(student1) << endl;
return 0;
}

  输出结果为 4

虚继承——基类含有虚函数指针,子类不含有虚函数指针

#include<iostream>
using namespace std;
class student
{
int a;
char c;
//static int b;
public:
//static void func();
virtual void fly();
};
class student1: virtual student
{
int d;
public:
void fly();
//virtual void eat();
};
int main()
{
cout << sizeof(student1) << endl;
return 0;

  此时输出为:20

解析:因为虚继承会再产生一个虚函数指针,去指向对应的基类,防止子类继承多个一样的基类,造成资源浪费

虚继承:子类和父类都有虚函数

#include<iostream>
using namespace std;
class student
{
int a;
char c;
//static int b;
public:
//static void func();
virtual void fly();
};
class student1: virtual student
{
int d;
public:
void fly();
virtual void eat();
};
int main()
{
cout << sizeof(student1) << endl;
return 0;
}

  输出:24

解析:此时是子类声明的虚函数是父类没有的,则此时子类会再产生一个虚函数指针,如果此时子类的所有虚函数都是继承自基类的,则不会产生虚函数指针。

struct和class内存大小的计算的更多相关文章

  1. C++类所占内存大小计算

    C++类所占内存大小计算 说明:笔者的操作系统是32位的. class A {}; sizeof( A ) = ? sizeof( A ) = 1明明是空类,为什么编译器说它是1呢? 空类同样可以实例 ...

  2. 计算Java对象内存大小

    摘要 本文以如何计算Java对象占用内存大小为切入点,在讨论计算Java对象占用堆内存大小的方法的基础上,详细讨论了Java对象头格式并结合JDK源码对对象头中的协议字段做了介绍,涉及内存模型.锁原理 ...

  3. python 计算apache进程占用的内存大小以及占物理内存的比例

      目的:计算所有apache进程占用的内存大小以及占物理内存的比例: 思路:利用系统中/proc/meminfo的现有数据进行统计 1.pidof列出服务对应进程的PID [root@yanglih ...

  4. 一道题看懂OC的文件管理:NSFileManager,计算文件包含内存大小

    计算文件夹下所有文件的大小 // 查看错误信息 __autoreleasing NSError *error; // 文件管理对象 NSFileManager *manager = [NSFileMa ...

  5. Java对象的内存布局以及对象所需内存大小计算详解

    1. 内存布局 在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 1) 对象头(Header): ...

  6. Ehcache计算Java对象内存大小

    在EHCache中,可以设置maxBytesLocalHeap.maxBytesLocalOffHeap.maxBytesLocalDisk值,以控制Cache占用的内存.磁盘的大小(注:这里Off ...

  7. HDP3.1 中 YRAN 和 MR2 的内存大小配置的计算方式

    Container 是 YARN 中基本的处理单元,它是对内存.CPU等计算的封装.总的来说,每个core每块硬盘 分配2个 container,能获得较好的集群利用率. 1. 确定可用内存大小. 对 ...

  8. 【转】C/C++ struct/class/union内存对齐

    原文链接:http://www.cnblogs.com/Miranda-lym/p/5197805.html struct/class/union内存对齐原则有四个: 1).数据成员对齐规则:结构(s ...

  9. C/C++中struct/union/class内存对齐

    struct/union/class内存对齐原则有四个: 1).数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储 ...

随机推荐

  1. 利用 Symbol Type Viewer 工具实现将 pdb 文件 转换为 c\c++ 头文件

    利用 Symbol Type Viewer 工具实现将 pdb 文件 转换为 c\c++ 头文件 一.得到符号 二.将符号转换为 .h 文件 三.得到 c\c++ 头文件,之后编程时直接导入这个文件即 ...

  2. Tomcat 简单容器化

    Tomcat 容器化 思考 问题1 , Tomcat 容器化,Tomcat 如何配置 APR 连接器 Tomcat 的基础镜像已经是开启了 APR. 问题2, Tomcat 是每次都需要重新构建. 一 ...

  3. 古老的txt下传和txt上载

    1.下传文件 TYPES:BEGIN OF TY_DATA, A2 TYPE CHAR20, B2 TYPE I, C2 TYPE CHAR20, END OF TY_DATA. DATA:IT_DA ...

  4. linux 环境下部署 Asp.Net Core 项目 访问 oralce 数据库

    1.ASP.NET Core 是一个跨平台的高性能开源框架,可以部署到Linux上,那项目部署在Linux上有哪些好处呢? 1.linux硬件需求小,大部分版本免费,成本低. 2.linux的用户管理 ...

  5. JavaScript RegExp(正则表达式) 对象

    正则表达式是描述字符模式的对象.正则表达式用于在文本上执行模式匹配和“搜索和替换”功能. var patt = /JC2182/i 示例说明: /JC2182/i - 是一个正则表达式. JC2182 ...

  6. 关于javascript,多种函数封装!!

    1.获取最终的属性 function getStyleAttr(obj, attr){ if(window.getComputedStyle){ return window.getComputedSt ...

  7. React的jsx语法,详细介绍和使用方法!

    jsx语法 一种混合使用html及javascript语法的代码 在js中 遇到<xx>即开始html语法 遇到</xx>则结束html语法 恢复成js语法 例如: let D ...

  8. youtube视频在线下载

    youtube视频在线下载网站: https://www.clipconverter.cc/ youtube视频样例: https://www.youtube.com/watch?v=NMkgz0AR ...

  9. 图片在View中的几种填充方式

    UIViewContentMode各类型效果   UIViewContentMode typedef enum {     UIViewContentModeScaleToFill,     UIVi ...

  10. flink KMeans算法实现

    更正:之前发的有两个错误. 1.K均值聚类算法 百度解释:k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类 ...