更多精彩内容请访问我的新博客站点

文章目录

  • sizeof 运算符
  • 不同数据类型所占的内存大小
  • 共用体的大小
  • 结构体的大小
  • 嵌套结构体的大小
  • 混合结构体的大小
  • 类对象的大小

sizeof 运算符

需要注意的是 sizeof() 是运算符,而不是一个函数,在编译时就计算好了,用于计算数据空间的字节数。因此,sizeof 不能用来返回动态分配的内存空间的大小。sizeof 常用于返回类型和静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。

本文将介绍使用 sizeof 来判定 共用体结构体嵌套结构体混合结构体 以及 类对象 所占空间的大小。


不同数据类型所占的内存大小

32 位 64 位
char 1 1
int 4 4
short 2 2
long 4 8
float 4 4
double 8 8
指针 4 8

long 类型与指针类型在 32 位机器上只占 4 字节,在 64 位机器上占 8 字节。其他类型在 32 位机器和 64 位机器都是占同样的大小空间。


共用体的大小

union A{int a[5];char b;double c;
};cout << sizeof(A) << endl;

上面求出共用体的大小为:24

union 中变量共用内存,应以最长的为准,A 中最长的成员是数组 a,其长度为 20。与结果不一样,这是因为在共用体内变量的默认对齐方式,必须以最长的 double(8Byte)对齐,所以得到 sizeof(A) = 24。所以将共用体内的 int a[5] 修改成 int a[6] 后,结果仍然不变;但如果将 int a[5] 修改成 int a[7],结果就变成 32。

对齐系数:每个平台上的编译器都有默认对齐系数 n,但是可以通过 #pragma pack(n) 来设定。

有效对齐系数:对于一个复杂类型变量,有效对齐系数 = min(对齐系数 n,复杂类型中最长数据类型的长度)。比如设定的对齐系数为 8,而结构体中最长的是 int,4个字节,那么有效对齐值为 4。

通过下面的例子说明有效对齐系数:

#pragma pack(4)union A{int a[5];char b;double c;
};cout << sizeof(A) << endl;

输出为:20

这是因为通过 #pragma pack(n) 设置对齐系数为 4,所以实际的有效对齐系数为:min(4, sizeof(double)) = 4,所以最后共用体 A 的大小为 5*int(4) = 20。


结构体的大小

首先介绍一个概念和两条原则:

偏移量 :偏移量指的是 结构体变量中成员的地址结构体变量地址 的差。

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

  1. 结构体变量中成员的偏移量必须是成员大小的整数倍。
  2. 结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。

例子:

struct B{char a;double b;int c;
};cout << sizeof(B) << endl;

输出为:24

这是因为 char a 的偏移量为 0,占用 1Byte;double b 指的下一个可用的地址的偏移量为 1,不是 sizeof(double)=8 的整数倍,需要补足 7Byte 才能是偏移量为 8;int c 指的下一个可用的地址的偏移量为 16,是 sizeof(int)=4 的整数倍,满足 int 的对齐方式。

故所有成员的变量都分配了空间,空间总的大小为 1+7+8+4 = 20,不是结构的节边界数(即结构中占用最大空间的类型所占用的字节数 sizeof(double)=8)的倍数,所以需要填充 4Byte,以满足结构的大小为 sizeof(double)=8 的倍数,即 24 。


嵌套结构体的大小

对于嵌套的结构体,需要将其展开。对嵌套结构体求 sizeof 时,上述原则变为:

  1. 展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。
  2. 结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。

例子:

struct C{char a;struct{char b;int c;} ss;short d;
};cout << sizeof(C) << endl;

输出:16

char a 的偏移量为 0,占用 1Byte;但是对于展开后的结构体的第一个成员 char b,下一个可用的地址的偏移量为 1,不是被展开结构体中最大成员 int c 的整数倍,需补充 3Byte 才能是偏移量变为 4;char b 占用 1Byte,下一个可用地址的偏移量是 5,又不是 int c 大小的整数倍,又需补充 3Byte 变为 8;short d 的偏移量为 12,满足 short 的对齐方式。

故所有成员变量都分配了空间,空间总的大小为 1+3+1+3+4+2 = 14,结尾还得填充 2Byte,以满足为 4 的倍数,所以总的大小为 16。


混合结构体的大小

混合结构体指的是结构体中包含有共用体(或数组)等比较复杂的结构体。如下面的例子:

#include <iostream>
using namespace std;
typedef union{long i;int k[5];char c;
} UDATE;
struct data{int cat;UDATE cow;double dog;
}too;
UDATE temp;
int main(){cout << sizeof(struct data) + sizeof(temp) << endl;return 0;
}

摘自《后台开发:核心技术与应用实践》例1.16,书中后面的解释有部分错误。

输出:64

假设测试机器是 64 位。UDATE 是一个 union,作为变量公用空间。里面占用字节数最多的变量是数组 int k[5],有 20Byte,但是它要与 long 类型的 8Byte 对齐,所以占用 24Byte。data 是一个 struct,每个变量分开占用空间,依次为 int(4+4) + UDATE(24) + double(8) = 40,字节已对齐,故 sizeof(struct data) 是 40。所以最后的结果为 40+24 = 64。


类对象的大小

关于类占用的内存空间,有以下几点需要注意:

  1. 如果类中含有虚函数,则编译器需要为类构建虚函数表,类中需要存储一个指针指向这个虚函数表的首地址,注意不管有几个虚函数,都只建立一张表,所有的虚函数地址都存在这张表里,类中只需要一个指针指向虚函数表首地址即可。

  2. 类中的静态成员是被类所有实例所共享的,它不计入sizeof计算的空间。

  3. 类中的普通函数或静态普通函数都存储在栈中,不计入sizeof计算的空间。

  4. 类成员采用字节对齐的方式分配空间。

例子:

class B{public:virtual void funa();virtual void funb();void func();static void fund();static int si; private:char c;int i;
};

以上类的大小:sizeof(B) = 12(32位)sizeof(B) = 16(64位)

根据以上的规则,多个虚函数只建立一张虚函数表,类中只存有一个指向虚函数表首地址的指针;普通函数 func() 不计入;静态成员 fund()si 也不计入;char c 占用 1Byte,再需补充 3Byte;int i 占用 4Byte。所以总的大小为:一个指针大小+1+3+4。32位系统指针大小为 4Byte,所以为 12Byte;64位系统指针大小为 8Byte,所以总大小为 16Byte。


C/C++中 sizeof 的用法总结相关推荐

  1. 64位linux,sizeof(int),C中sizeof()的用法——32位和64位下的sizeof()

    机器平台:X86_64 处理器 操作系统:Red Hat 4.1.2-14 编译器: gcc version 4.1.2 20070626 Size of char is:               ...

  2. C语言中sizeof()的用法

    只要参加软件研发的笔试(C/C++)几乎都会涉及到sizeof()的用法,我昨天也遇到了,有的也会,但是真正sizeof()的核心还是没有领会,今天上网,无聊中就看到了详细的sizeof()的阐述,现 ...

  3. c语言中size of 用法,C语言中sizeof()的用法

    要参加软件研发的笔试(C/C++)几乎都会涉及到sizeof()的用法,我昨天也遇到了,有的也会,但是真正sizeof()的核心还是没有领会,今天上网,无聊中就看到了详细的sizeof()的阐述,现在 ...

  4. C/C++常用宏定义,注意事项,宏中#和##的用法

    总结下宏和函数的不同之处,以供大家写代码时使用,这段总结摘自<C和指针>一书. 当然宏定义非常重要的,它可以帮助我们防止出错,提高代码的可移植性和可读性等. 下面列举一些成熟软件中常用得宏 ...

  5. c++ memset 语言_C++中memset函数用法详解

    本文实例讲述了C++中memset函数用法.分享给大家供大家参考,具体如下: 功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值,块的大小由第三个参数指定,这个函数通常 ...

  6. [c、c++]宏中#和##的用法(zz)

    http://blog.csdn.net/blackbillow/article/details/3850587 [c.c++]宏中"#"和"##"的用法(zz ...

  7. C和C++中static的用法及友元

    C和C++中static的用法 文章目录 C和C++中static的用法 一.**C语言中**: 二.**C++中**: 三.**友元**: 一.C语言中: static 修饰全局变量表示该变量只在本 ...

  8. socket android用法,Android NDK中socket的用法以及注意事项分析

    与Java层中的套接字相比,本机层中的Socket可以选择更多的配置项,并获得关于当前拥塞状态的更准确的信息,那么 NDK中socket的用法以及注意事项分析,大家清楚吗?下文是爱站技术频道小编为大家 ...

  9. c语言 sizeof typeof,typeof、nameof、sizeof的用法

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? typeof.nameof.sizeof的用法 这些都是较直觉的用法,故只列范示,说明的部分会比较少 一.nameofu ...

最新文章

  1. 使用redis和mysql的开源项目_干货!带你了解为什么那么多开源项目都是用Redis!...
  2. 大脑奖获得者Peter Dayan:生物决策机制为生存铺路,预编程是本能!
  3. VTK:图片之ImageCheckerboard
  4. P2082 区间覆盖(加强版)
  5. 深度学习 占用gpu内存 使用率为0_你了解GPU吗?为什么说深度学习需要GPU?
  6. 无法连接 服务器/虚拟机中的数据库,报错Access denied for user ‘root‘@‘192.168.1.101‘
  7. Python的GUI框架PySide
  8. linux下安装dovecot
  9. python中add_Python add()函数是如何使用呢?
  10. 当Elasticsearch遇见智能客服机器人
  11. Code Review:C#与JAVA的哈希表内部机制的一些区别
  12. mysql主从备份 ssl_基于SSL的mysql主从复制
  13. 接口与抽象类的区别和相同点
  14. SoapUI中文乱码
  15. 嵌入式开发|STM32工程中添加Bootloader实现串口程序下载
  16. 【Web技术】1139- 手把手教你实现手绘风格图形
  17. 第三方登录—QQ登录
  18. @click.stop作用(阻止点击事件继续传播,即阻止事件冒泡)
  19. 素数回文(打表到文件里面)
  20. 带附件/密送/抄送的 javaMail 邮件发送 -- java_demo(两种实现方式)

热门文章

  1. Windows10/11在使用微软账号登录后无法远程桌面
  2. gog无效的验证码_如何退款GOG游戏
  3. 腾讯云11·11:千亿订单背后的安全“暗战”
  4. 大数加法(ascll转换),利息计算(数组,sizeof与循环运用)
  5. all index range ref eq_ref const system 索引type说明
  6. c# 方法参数 传值or传引用?(ref,out,可变参数params,可选参数,命名参数)
  7. 【大一大二必看】计算机专业的同学应该参加哪些比赛?
  8. 射影几何----第四调和点的作图法及证明
  9. UBUNTU ifconfig只有lo
  10. Baxter学习笔记1-机器人软硬件配置篇