热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析C语言中结构体的内存对齐机制及其优化方法

为了提高CPU访问效率,C语言中的结构体成员在内存中遵循特定的对齐规则。本文详细解析了这些对齐机制,并探讨了如何通过合理的布局和编译器选项来优化结构体的内存使用,从而提升程序性能。

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

为了让CPU能够更舒服地访问到变量,struct中的各成员变量的存储地址有一套对齐的机制。这个机制概括起来有两点:第一,每个成员变量的首地址,必须是它的类型的对齐值的整数倍,如果不满足,它与前一个成员变量之间要填充(padding)一些无意义的字节来满足;第二,整个struct的大小,必须是该struct中所有成员的类型中对齐值最大者的整数倍,如果不满足,在最后一个成员后面填充。

各种类型的变量的align值如下,参考的是wikipedia的页面:Data structure alignment

The following typical alignments are valid for compilers from Microsoft, Borland, and GNUwhen compiling for 32-bit x86:

  • char (one byte) will be 1-byte aligned.
  • short (two bytes) will be 2-byte aligned.
  • An int (four bytes) will be 4-byte aligned.
  • float (four bytes) will be 4-byte aligned.
  • double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux.
  • long double (twelve bytes) will be 4-byte aligned on Linux.
  • Any pointer (four bytes) will be 4-byte aligned on Linux. (eg: char*, int*)

The only notable difference in alignment for a 64-bit linux system when compared to a 32 bit is:

  • double (eight bytes) will be 8-byte aligned.
  • long double (Sixteen bytes) will be 16-byte aligned.
  • Any pointer (eight bytes) will be 8-byte aligned.


这里写了个程序来验证这些事:

#include struct s {char a;short b;char c;double d;char e;
};int main() {struct s s1;printf("%d, %d, %d, %d, %d\n",(char*)(&s1.a) - (char*)(&s1),(char*)(&s1.b) - (char*)(&s1),(char*)(&s1.c) - (char*)(&s1),(char*)(&s1.d) - (char*)(&s1),(char*)(&s1.e) - (char*)(&s1));printf("%d\n", sizeof(struct s));return 0;
}

在64位linux下面运行这段代码的结果是:

0, 2, 4, 8, 16
24

由于对齐机制的存在,实际上上面的struct在内存中是长这个样子的,共计24个字节:

struct s {char a; //在地址为0的位置char padding1[1]; //由于下面一个元素是short,对齐字节数为2的位数,需要补1字节short b; //对齐到了地址为2的位置char c; //在地址为4的位置char padding2[3]; //由于下面一个元素是double,对齐字节数为8的倍数,需要补3字节double d; //对齐到了地址为8的位置char e; //在地址为16的位置char padding3[7]; //整个struct的大小需要是对齐数最大者,也就是double的8字节的整数倍
};

如果是在32位的linux下跑上面的程序,由于double的长度还是8字节,但是对齐是4字节的了,所以前面几个成员的位置不变,而最后的padding只需要补3个字节就可以了,所以输出的结果是0, 2, 4, 8, 16及20.

对于windows,其32位和64位下double都是8字节对齐的,所以在32位和64位下跑这个程序结果都是0, 2, 4, 8, 16及24.

最后,整个struct的大小的要求是对齐值最大者的整数倍,没有什么默认的4或者8的倍数一说。如果把上面程序中的a,b,c,d,e的类型全变成char,那么最后的他们的地址会是0,1,2,3,4,整个struct的大小 sizeof(struct s)的值是5,没有任何padding发生。

以上程序实验的环境在64位centos x64上的gcc 4.1.2(32位结果加-m32参数)及Visual Studio 2008上得出。


转:https://my.oschina.net/scriptboy/blog/61575



推荐阅读
  • WinMain 函数详解及示例
    本文详细介绍了 WinMain 函数的参数及其用途,并提供了一个具体的示例代码来解析 WinMain 函数的实现。 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 检查在所有可能的“?”替换中,给定的二进制字符串中是否出现子字符串“10”带 1 或 0 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 在Windows系统中安装TensorFlow GPU版的详细指南与常见问题解决
    在Windows系统中安装TensorFlow GPU版是许多深度学习初学者面临的挑战。本文详细介绍了安装过程中的每一个步骤,并针对常见的问题提供了有效的解决方案。通过本文的指导,读者可以顺利地完成安装并避免常见的陷阱。 ... [详细]
  • 题目《BZOJ2654: Tree》的时间限制为30秒,内存限制为512MB。该问题通过结合二分查找和Kruskal算法,提供了一种高效的优化解决方案。具体而言,利用二分查找缩小解的范围,再通过Kruskal算法构建最小生成树,从而在复杂度上实现了显著的优化。此方法不仅提高了算法的效率,还确保了在大规模数据集上的稳定性能。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 你的问题在于:1. 代码格式混乱,缺乏必要的缩进,导致可读性极低;2. 使用 `strlen()` 和 `malloc()` 函数时,必须包含相应的头文件;3. `write()` 函数的返回值处理不当,建议检查并处理其返回值以确保程序的健壮性。此外,建议在编写代码时遵循良好的编程规范,增加代码的可维护性和可读性。 ... [详细]
  • [c++基础]STL
    cppfig15_10.cppincludeincludeusingnamespacestd;templatevoidprintVector(constvector&integer ... [详细]
  • String字符串与字符数组#includeStringintmain(){char*strhello;字符串与字符数组的关系:字符串是 ... [详细]
  • Visual Studio Code (VSCode) 是一款功能强大的源代码编辑器,支持多种编程语言,具备丰富的扩展生态。本文将详细介绍如何在 macOS 上安装、配置并使用 VSCode。 ... [详细]
  • window下的python安装插件,Go语言社区,Golang程序员人脉社 ... [详细]
  • 本文介绍了一种在ANSI C中动态分配二维数组的方法。通过创建指针数组并为每个指针分配连续空间,可以灵活地管理内存。文章还讨论了一些常见的错误和注意事项。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
author-avatar
肉斯情-
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有