C++ | 结构体及大小计算

news/2024/10/19 6:25:52/

C++结构体及大小计算


文章目录

  • C++结构体及大小计算
    • struct 和 class 区别
    • 字节对齐
      • 默认对齐方式
    • 位域
    • 使用#pragma pack(n)
    • 结构体中有结构体
    • Reference

struct 和 class 区别

结构体(struct)和类(class)有点像,均是定义一个数据单元,该数据单元中包含多个类型的数据,即成员变量,也可以包含多个方法。

创建结构体就像创建对象一样,一个对象有多个属性。

区别如下:

  • 结构体使用关键字 struct ,类使用关键字 class;
  • 通常情况下结构体声明只会声明成员变量,如果包含成员函数,就和类相似;
  • 结构体声明通常不包括 public 或 private 的访问修饰符;
  • 类成员默认情况是 private 的,而结构体的成员则默认为 public。

字节对齐

struct 的 sizeof 是所有成员字节对齐后长度相加,而 union 的 sizeof 是取最大的成员长度。

可以通过下面的方法来改变默认的对齐条件:

(1) 伪指令#pragma pack(n):C编译器将按照n个字节对齐。

(2) 伪指令#pragma pack():取消自定义字节对齐方式。

字节对齐的细节和编译器实现相关

一般而言,满足3个准则:

(1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除,即 最宽成员大小 首成员大小 = 整数 \frac{最宽成员大小}{首成员大小} = 整数 首成员大小最宽成员大小=整数

(2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是该成员大小的整数倍,即 偏移量 该成员大小 = 整数 \frac{偏移量}{该成员大小} = 整数 该成员大小偏移量=整数。如有需要编译器会在成员之间加上填充字节。

(3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节,即 结构体大小 最宽成员大小 = 整数 \frac{结构体大小}{最宽成员大小} = 整数 最宽成员大小结构体大小=整数

基本类型是指: char、short、int、float、double 等内置数据类型。

如果一个结构体中包含另外一个结构体成员,那么此时最宽基本类型成员取最宽的基本类型。

默认对齐方式

测试机器为64位ubuntu电脑

#include <iostream>using namespace std;typedef struct
{char randy1;  // 1个字节   / 1字节char randy2;  // 1个字节   / 2字节char randy3;  // 1个字节   / 3字节
}Q1;              // total size : 3typedef struct
{int num;     // 4个字节char randy;  // 1个字节,补齐为8字节
}Q2;             // total size : 8typedef struct
{char randy;  // 1个字节   / 1字节int num;     // 4个字节   / 5字节 -> 补齐3字节,共8字节
}Q2_1;             // total size : 8typedef struct
{char randy;      // 1字节   / 1字节int sesame;      // 4字节   / 5字节 -> 补齐3字节,共8字节long long  qcj;  // 8字节   / 16字节char kim;        // 1字节   / 17字节 -> 补齐7字节,共24字节
}Q3;                 // total size : 24typedef struct
{char randy;      // 1字节   / 1字节char kim;        // 1字节   / 2字节int sesame;      // 4字节   / 6字节 -> 补齐2字节,共8字节long long  qcj;  // 8字节   / 16字节
}Q3_1;               // total size : 16typedef struct
{long sesame;     // 8字节 / 8字节char * pRandy;   // 8字节 / 16字节short int data;  // 2字节 / 18字节char randy;      // 1字节 / 19字节 -> 补齐5字节
}Q4;                 // total size : 24int main(void)
{char randy;cout << "char: " << sizeof(randy) << endl;// 1char* pRandy;cout << "char *: " << sizeof(pRandy) << endl;// 8int sesame;cout << "int: " << sizeof(sesame) << endl;// 4short int shint;cout << "short int: " << sizeof(shint) << endl;// 2long qcj;cout << "long: " << sizeof(qcj) << endl;// 8long long qccccccccj;cout << "long long: " << sizeof(qccccccccj) << endl;// 8cout << "Q1: " << sizeof(Q1) << endl;      // Q1: 3cout << "Q2: " << sizeof(Q2) << endl;      // Q2: 8cout << "Q2_1: " << sizeof(Q2_1) << endl;  // Q2_1: 8cout << "Q3: " << sizeof(Q3) << endl;      // Q3: 24cout << "Q3_1: " << sizeof(Q3_1) << endl;  // Q3_1: 16cout << "Q4: " << sizeof(Q4) << endl;      // Q4: 24return 0;
}

位域

位域:指定某个成员变量所占用的二进制位数(Bit)

位域的宽度不能超过它所依附的数据类型的长度

如果指定了 char ch1:3,则ch1最多只能表示3个bit的char,最大不能超过8bit的char,其他基本类型依此类推。

#include <iostream>using namespace std;typedef struct
{char ch1:1; // 1+3+3=7位,所以只占1个字节char ch2:3;char ch3:3;
}Q1;              // total size : 1 Bytestypedef struct
{char ch1 : 5; // 5+5+3=13位,所以只占2个字节char ch2 : 5;char ch3 : 3;
}Q2;              // total size : 2 Bytestypedef struct
{char ch1 : 5; // 5+5+4=14bit,占3个字节char ch2 : 5;char ch3 : 4;
}Q3;              // total size : 3 Bytestypedef struct
{char ch1 : 7; // 7+7=14位,却只占2个字节 【注意】char ch2 : 7;
}Q4;              // total size : 2 Bytestypedef struct
{char ch1 : 1; // 偏移1个bitint a : 16;   // 偏移16个bitint b : 16;   // 偏移16个bit
}Q5;              // total size : 8 Bytestypedef struct
{char ch1 : 1; int a : 16;int b : 17;
}Q6;              // total size : 8 Bytesint main(void)
{cout << "Q1: " << sizeof(Q1) << endl;  // Q1: 1cout << "Q2: " << sizeof(Q2) << endl;  // Q2: 2cout << "Q3: " << sizeof(Q3) << endl;  // Q3: 3cout << "Q4: " << sizeof(Q4) << endl;  // Q4: 2cout << "Q5: " << sizeof(Q5) << endl;  // Q5: 8cout << "Q6: " << sizeof(Q6) << endl;  // Q6: 8return 0;
}

使用#pragma pack(n)

#include <iostream>
using namespace std;#pragma pack(1) // 要求补齐为“1”的倍数
typedef struct
{char randy; // 1 字节 / 1 字节,由于自定义了对齐方式,所以不再补齐int b;      // 4字节 / 5 字节int a;      // 4字节 / 9 字节
}Q1;            // total size : 9 Bytes#pragma pack(2) // 要求补齐为“2”的倍数
typedef struct
{char randy; // 1+1 字节,由于自定义了对齐方式,补齐为"2"的倍数int b;      // 4字节 /6 字节int a;      // 4字节 /10 字节
}Q2;            // total size : 10 Bytes#pragma pack(4) // 要求补齐为“2”的倍数
typedef struct
{char randy;    // 1+1 字节,由于自定义了对齐方式,补齐为"2"的倍数int b;         // 4字节 /6 字节short int a;   // 2字节 /8 字节int c;         // 4字节 /12 字节
}Q2_1;             // total size : 16 Bytes#pragma pack(2)  // 要求补齐为“2”的倍数
typedef struct
{char randy; // 1 字节 / 2 字节 -> 补齐1字节,由于自定义了对齐方式,补齐为"2"的倍数int b;      // 4 字节 / 6 字节int a;      // 4 字节 / 10 字节
}Q3;            // total size : 10 Bytes#pragma pack(4)  // 要求补齐为“4”的倍数
typedef struct
{char randy; // 1 字节 / 4 字节 -> 补齐3字节,由于自定义了对齐方式,补齐为"2"的倍数int b;      // 4 字节 / 8 字节int a;      // 4 字节 / 12 字节
}Q3_1;          // total size : 12 Bytes#pragma pack(2)  // 要求补齐为“2”的倍数
typedef struct
{char randy;     // 1 字节 / 2 字节 -> 补齐1字节,由于自定义了对齐方式,补齐为"2"的倍数int b;          // 4 字节 / 6 字节short int c;    // 2 字节 / 8 字节
}Q3_2;              // total size : 8 Bytes#pragma pack(4)
typedef struct
{long sesame;     // 8字节 / 8字节char * pRandy;   // 8字节 / 16字节short int data;  // 2字节 / 18字节char randy;      // 1字节 / 20字节 -> 补齐1字节
}Q4;                 // total size : 20int main(void)
{cout << "Q1: " << sizeof(Q1) << endl;     // Q1: 9cout << "Q2: " << sizeof(Q2) << endl;     // Q2: 10cout << "Q2_1: " << sizeof(Q2_1) << endl; // Q2_1: 10cout << "Q3: " << sizeof(Q3) << endl;     // Q3: 10cout << "Q3_1: " << sizeof(Q3_1) << endl; // Q3_1: 12cout << "Q3_2: " << sizeof(Q3_2) << endl; // Q3_2: 8cout << "Q4: " << sizeof(Q4) << endl;     // Q4: 20return 0;
}

当 #pragma pack 的 n 值等于2的指数倍,如 $2^0, 2^1, 2^2, 2^3 $,若 n 超过所有数据成员长度的时候,这个 n 不产生任何效果。

结构体中有结构体

计算时仅需将内嵌的结构体展开即可

但是计算大小时,展开后的结构体的第一个成员的偏移量应当是被展开的结构体中宽度最大成员的整数倍,即 内嵌结构体最宽成员大小 首成员大小 = 整数 \frac{内嵌结构体最宽成员大小}{首成员大小} = 整数 首成员大小内嵌结构体最宽成员大小=整数

#include <iostream>using namespace std;typedef struct
{short c;    // 2 字节 / 2 字节char randy; // 1 字节 / 4 字节 -> 补齐1字节int sesame; // 4 字节 / 8 字节int kim;    // 4 字节 / 12 字节
}Q1;            // total size : 12 bytestypedef struct
{short randy;     // 2字节 / 4 字节 -> 补齐2字节, 展开后的结构体的最大成员宽度为4struct{char randy; // 1 字节 / 8 字节 -> 补齐3字节 int jun;    // 4 字节 / 12字节}Q;int kim;        // 4 字节 / 16字节}Q2;            // total size : 16 bytesint main(void)
{cout << "Q1: " << sizeof(Q1) << endl; // Q1: 12cout << "Q2: " << sizeof(Q2) << endl; // Q2: 16return 0;
}

Reference

  • C++中的结构体所占内存空间总结

欢迎关注公众号【三戒纪元】


http://www.ppmy.cn/news/64510.html

相关文章

什么是应用交付网络(ADN)

从CDN到ADN CDN&#xff08;内容分发网络&#xff09;在90年代末受到麻省理工学院的启发并完成发明&#xff0c;00年代初成立第一家成功的CDN商业企业Akamai。CDN的目标是相对于最终用户在空间上分配服务&#xff0c;以提供高可用性和高性能。随着互联网的发展&#xff0c;CDN…

设计模式(二):依赖倒转原则(详解)

依赖倒转原则 前言一、依赖倒转原则1、基本介绍2、依赖关系传递的三种方式3、注意事项 二、代码演示1、版本一2、版本二3、版本三 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注博主&#xff01;也许一个人独行&am…

Http 响应头 Transfer-Encoding : chunked 导致 浏览器客户端请求错误问题

生产环境服务器规划如下 服务器类型网络环境cal.comnginx外网192.168.7.15:9200tomcat内网192.168.7.16:9200tomcat内网sdd.comnginx内网192.168.7.15:9100tomcat内网192.168.7.16:9100tomcat内网 192.168.7.15和192.168.7.16是做个负载均衡。目前的需求是用户访问外网的cal.…

【存储数据恢复】NetApp存储WAFL文件系统数据恢复案例

存储数据恢复环境&#xff1a; NetApp存储设备&#xff0c;WAFL文件系统&#xff0c;底层是由多块硬盘组建的raid磁盘阵列。 存储故障&#xff1a; 工作人员误操作导致NetApp存储内部分重要数据被删除。 存储数据恢复过程&#xff1a; 1、将存储设备的所有磁盘编号后取出&…

springboot + vue 部署 阿里云云服务器 ECS

安装所需文件 安装mysql5.7 下载MySQL的yum源配置 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm安装MySQL的yum源 yum -y install mysql57-community-release-el7-11.noarch.rpm使用yum方式安装MySQL5.7&#xff08;下载需要点时间&#xf…

面试官:一千万的数据,你是怎么查询的

很多小伙伴一看到一些千万级数据之类的面试题就不知道怎么去回答。 也许有些人没遇过上千万数据量的表&#xff0c;也不清楚查询上千万数据量的时候会发生什么。 今天就来带大家实操一下&#xff0c;这次是基于MySQL 5.7.26做测试 准备数据 没有一千万的数据怎么办&#xf…

生成式AI对Java中的Calendar的深度研究报告

ChartGPT Java中的Calendar类是一个用于处理日期和时间信息的工具类。它允许我们在程序中创建和操作日期和时间对象&#xff0c;进行日期和时间的计算、比较和格式化等操作。 首先&#xff0c;Calendar类是一个抽象类&#xff0c;不能直接实例化。我们可以通过调用其静态方法…

深入理解java虚拟机精华总结:运行时栈帧结构、方法调用、字节码解释执行引擎

深入理解java虚拟机精华总结&#xff1a;运行时栈帧结构、方法调用、字节码解释执行引擎 运行时栈帧结构局部变量表操作数栈动态连接方法返回地址 方法调用解析分派静态分派动态分派 基于栈的字节码解释执行引擎 运行时栈帧结构 Java虚拟机以方法作为最基本的执行单元&#xf…