结构体内存对齐

如何计算结构体的大小?

首先得掌握结构体的对齐规则:

1.第一个成员在与结构体变量偏移量为0的地址处。(将第一个成员放在结构体内存的第0处)

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。(从0地址处开始,偏移量逐渐增减,每个字节加一,第二个成员开始,将成员的字节大小跟对齐数(VS2019编译器的默认对齐数是 8)进行比较,选两者中较小的,把该变量放到小的对齐数的偏移量地址上)

对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。

  • VS中默认的对齐数为8
  • Linux - 没有默认对齐数的概念

3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。(如果全部成员自身的的大小已经放入内存,但最后一个成员的尾字节所在的偏移量不是最大对其数的整数倍,则在最后要浪费空间直到刚好到整数倍为止)

4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

struct S
{               //类型大小      VS默认对齐数         两者中小的对齐数char c1;     //  1              8                   1int i;      //  4              8                   4double d;   //  8              8                   8
};
int main()
{struct S s;printf("%d\n",sizeof(s)); //结构体大小为16,并不是简单的变量大小相加
}

为什么存在内存对齐?

大部分的参考资料都是这样说的:

1.平台原因(移植原因)︰不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

⒉.性能原因︰数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说︰

结构体的内存对齐是拿空间来换取时间的做法。


那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到∶

1.让占用空间小的成员尽量集中在一起。

2.修改默认对齐数

之前我们见过了#pragma这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。

#pragma pack(2)          //设置默认对齐数为2
struct s1
{char c1;int i;char c2;
};
#pragma pack()          //取消设置的默认对齐数,还原为默认

此时结构体大小为8,如果设置默认对齐数为1的话,则成员紧挨着存放,等于没有对齐


offsetof宏:

用于计算结构体中某变量相对于首地址的偏移量(以字节为单位)

函数原型:offsetof (type,member)

使用:

#include <stdio.h>
#include <stddef.h>       //需要引入头文件
struct s1
{char c1;int i;char c2;
};
int main()
{printf("%d\n", offsetof(struct s1, c1)); //0,C1在偏移量为0的地址处printf("%d\n", offsetof(struct s1, i));        //4,i在偏移量为4的地址处printf("%d\n", offsetof(struct s1, c2));    //8,C2在偏移量为8的地址处return 0;
}

模拟实现offsetof宏:

#include <stdio.h>
struct A
{char a;int b;char c;double d;
};
#define OFFSETOF(struct_name,mem_name) (int)&(((struct_name *)0)->mem_name)
int main()
{//模拟实现宏offsetofprintf("%d\n", OFFSETOF(struct A, a));printf("%d\n", OFFSETOF(struct A, b));printf("%d\n", OFFSETOF(struct A, c));printf("%d\n", OFFSETOF(struct A, d));return 0;
}

解释:定义宏时,将0强制转换为结构体类型,只是0不再是个整型,而是个地址,是结构体的首地址,并没有真正去创建结构体变量,然后通过->找到相应的结构体变量,&取出该变量的地址,减去0地址,再强制类型转换为int型,就能输出变量相对于首地址的偏移量,这里没有减-0,因为没有意义,如果规定首地址是0x10,那最后强转为int之前就要减去首地址0x10,才是偏移量

C语言结构体内存对齐相关推荐

  1. C语言结构体内存对齐问题

    参考博文:C语言结构体内存对齐问题 成员对齐:   以4字节对齐为例,如果自身类型小于4字节,则该成员的首地址是自身类型大小的整数倍:如果自身类型大于等于4字节,则该成员的首地址是4的整数倍.若内嵌结 ...

  2. 室友利用一把王者的时间就学会了【C语言结构体内存对齐】

    文章目录 一.什么是结构体内存对齐? 二.结构体的对齐规则 结构体内存对齐规则的具体应用 三.为什么会存在内存对齐 总结 提示:以下是本篇文章正文内容,下面案例可供参考 一.什么是结构体内存对齐? 从 ...

  3. c语言 char转int_图文并茂,一文讲透C语言结构体内存对齐

    ↑点击上方蓝色字体,关注"嵌入式软件实战派"获得更多精品干货. (以下有约5000字内容,建议收藏再读,推荐下载源码自行测试以加深理解.) 面试官:你知道C语言的结构体对齐吗? 应 ...

  4. C语言-结构体内存对齐

    C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...

  5. c语言结构体的对齐方式,C语言结构体内存的对齐知识详解

    前言 在前面的章节中,我们谈到了C语言中整数以及浮点数的储存 今天,我们来谈一谈一些关于结构体内存的知识. 我们先来看一个例子: struct S1 { char c1; int i; char c2 ...

  6. printf打印结构体_工程师:这道题80%初学者都没做对!你确定搞懂结构体内存对齐了?...

    这是工程师面试后的实际经历-- 这道经典.易错的关于C语言结构体内存对齐的题目,你真的会吗: 求32bit环境下以下结构体所占的字节数:typedef struct test_struct{ char ...

  7. 关于C语言中的结构体内存对齐与位段问题

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 结构体的内存对齐与位段 一.结构体的内存对齐 1.为什么会有内存对齐? 2.如何内存对齐 3. 如何在设计结构体的时候,既要 ...

  8. 语言结构体在内存的分布_结构体内存对齐,这篇文章给你彻底搞会!(干货收藏)...

    脚本之家 你与百万开发者在一起 公众号:C语言编程 作者:薛定谔的coding猫 一.内存对齐的原因  1.平台原因(移植原因):一些资料上是这样说的,"不是所有的硬件平台都能访问任意地址上 ...

  9. 细讲C语言结构体(结构体内存对齐你懂了吗?)

    结构体 结构体类型的声明 结构体自引用 结构体变量的定义和初始化 结构体内存对齐 结构体传参 结构体 结构体的声明 结构体是一些值集合的,里面可以包括char,int,double等等的各种类型构成的 ...

  10. 【C语言】自定义类型——计算结构体内存对齐

    文章目录 前言 一.结构体 结构体类型的声明 结构的自引用 结构体变量的定义和初始化 *结构体内存对齐 修改默认对齐数 结构体传参 结构体实现位段(位段的填充&可移植性) 二.枚举 枚举类型的 ...

最新文章

  1. 记录一次没有收集直方图优化器选择全表扫描导致CPU耗尽
  2. SAP QM 模块主数据
  3. vb.net机器学习-手写和本机数字识别-K均值和欧氏距离
  4. Linux综合练习——课件分发
  5. html5+php调用android手机图片,HTML5拍照上传图片Phonegap封装HTML5调用Android相机拍照上传到PHP端...
  6. LINUX给进程内容窗口改名的代码
  7. Android中应用程序获得系统签名权限(platform.x509.pem platform.pk8)下载地址
  8. PPAPI 插件编写
  9. H5+CSS前端特效源代码:可旋转动态日文片假名
  10. 时序数据获取 | Python实现时间序列数据集获取
  11. 淘宝店铺老店标识怎么显示 怎么淘宝老店标识申请
  12. gnu nano显卡测试软件,显卡天梯图2018年9月最新版 秒懂桌面显卡性能排行
  13. Lattice LSTM
  14. 【渗透测试工具beef】XSS渗透测试工具beef如何安装使用?
  15. 深度linux u盘启动安装教程,带你了解国产操作系统“深度(deepin)”之制作U盘启动教程...
  16. Android 12 小部件详解
  17. 计算机打开查看方式默认是什么样,如何设置电脑文件夹默认查看方式
  18. python-pyqt5-初识-2基本操作
  19. 敏之澳分享拼多多的宝贝标题要怎么写?
  20. 数字数据转换为字符数据_为什么替代数据对数字转换至关重要

热门文章

  1. U盘格式化后恢复,DiskGenius 4.9.6 海外注册版
  2. MATLAB线性规划相关函数用法
  3. mapgis6.7原创2019视频教程
  4. cwm oracle,ORA-06512: at OLAPSYS.CWM2_OLAP_UTILITY
  5. Zint生成多种条码及二维码
  6. Lantek钣金软件的介绍与安装
  7. java中模糊查询sql怎么写_java模糊查询sql语句
  8. 【行业专题报告】食品饮料、休闲零食、咖啡茶饮-专题资料
  9. smarty3中文手册
  10. android 开发种子文件,IT之家学院:如何制作种子文件和磁力链接