gcc数据对齐之: howto 1.
GCC支持用__attribute__为变量、类型、函数、标签指定特殊属性。这些不是编程语言标准里的内容,而属于编译器对语言的扩展。 本文介绍其中的两个属性:aligned和packed。
aligned
aligned属性最常用在变量声明上。它的作用是告诉GCC,为变量分配内存时,要分配在对齐的内存地址上。什么是对齐的内存地址呢?
一般计算机的内存是以字节(byte,等于8bit)为最小单元的。内存地址相当于从0开始的字节偏移数。如果一个内存地址是N的倍数,我们就说它是N字节对齐的(N-byte aligned)。
对于C/C++中的基本数据类型,假设它的长度为n字节,那么该类型的变量会被编译器默认分配到n字节对齐的内存上。例如,char的长度是1字节,char类型变量的地址将是1字节对齐的(任意值均可); int的长度是4字节,所以int类型变量将被分配到4字节对齐的地址上。这种默认情况下的变量对齐方式又称作自然对齐(naturally aligned)。
但是,有时候我们希望改变这种默认情况。这时候就可以使用aligned属性了。例如:
int x __attribute__ ((aligned (16))) = 0;
告诉编译器把变量x分配在16字节对齐的内存地址上,而非默认的4字节对齐。
编译器之所以默认让变量自然对齐,是因为这种对齐情况下的内存访问是最高效的。受限于硬件实现,非对齐内存访问的性能会有所下降;甚至在有些处理器(如DSP、早期的ARM)上,非对齐的内存访问根本就不支持, 将直接引发错误。而我们之所以需要自己指定对齐方式,很多时候是程序优化的需求。例如,在x86平台上要使用SSE指令,所操作的数据在内存中就必须是16字节对齐的。
aligned不仅可以用作变量属性,还能用作函数属性和数据类型属性。它作为函数属性时的作用等价于对函数使用-falign-functions这一优化选项。 当它用作数据类型的属性时,相当于告诉编译器,这一类型的所有变量都要按指定字节数对齐。
aligned与结构体
结构体是一种数据类型,它与aligned有一些特殊的关系。上面提到,aligned可以用于指定数据类型的属性,因此可以用于结构体,例如:
struct __attribute__ ((aligned (8))) my_struct1 {
short f[3];
};
但这么用不仅会影响为该结构体变量分配内存的位置,还可能影响其内存占用。在上面的例子中,这个结构体内有3个两字节的short,本来只需要占用6字节的内存; 但由于指定了8字节对齐,编译器会在该结构体尾部填充额外的2个字节,使得这个结构体的大小为8字节。为什么要填充多余的字节呢?因为只有将该结构体补足8个字节,才能保证在这个结构体类型的数组中,数组中每个元素 都是8字节对齐的(考虑到数组元素在内存中的连续存放)。
aligned也可以用在结构体的成员上,这时就成了对变量指定属性。GCC的相关文档里提到,C语言规定结构体类型必须至少对齐到其所有成员变量对齐字节数的最小公倍数, 因此指定结构体的对齐完全可以通过指定其中成员变量的对齐来实现,不过前者明显可读性好些。
当aligned属性用于数据类型(比如结构体)的时候,只能增加对齐字节数而不能减小。例如,下面的结构体本身大小有6字节,虽然指定了4字节对齐,但并不能达到目的,最终GCC还是会按8字节对齐处理。
struct __attribute__ ((aligned (4))) my_struct2 {
short f[3];
};
如果要减小对齐字节数,需要用到下面介绍的packed属性。
packed
packed属性的主要目的是让编译器更紧凑地使用内存。当它用于变量时,告诉编译器该变量应该有尽可能小的对齐,也就是1字节对齐。当它用于结构体时 ,相当于给该结构体的每个成员加上了packed属性,这时该结构体将占用尽可能少的内存。例如:
struct __attribute__ ((packed)) my_struct3 {
char c;
int i;
};
这个结构体被指定了packed,所以它的成员变量将是1字节对齐的,也就是说成员i将紧跟着成员c,从而使得该结构体的实际大小为5字节。 如果不指定packed,由于要满足成员i的4字节对齐要求(它是int型的),编译器将在成员c之后填充3个字节,使得这个结构体实际大小变为8字节。
采用packed属性虽然可以节省内存,但它会导致非对齐的内存访问。例如上述结构体的int型成员变量i,它的内存地址将不是4的倍数,访问它时就是非对齐访问。 当用.或->操作符存取结构体成员时,编译器会保证存取到正确的值;但如果用指针直接访问非对齐的成员变量,就只能指望处理器支持非对齐访问了,否则将会出错。 这也是很多人认为给结构体指定packed属性不太安全的原因。
什么时候用packed?
上面说到使用packed可能“不安全”,但为什么还要用呢?什么时候会需要它呢?
使用packed最重要的场合莫过于处理跟文件格式或网络协议有关的二进制数据了。这些格式或协议是不能容忍多余字节的,所以当用结构体表示其数据时,必须阻止编译器填充字节。 这正是packed的设计初衷。
另外还可以用packed来节省内存,不过这是以牺牲性能为代价的,不是什么好方法。通过适当排列结构体成员的顺序可以使得需要填充的字节数尽可能少,这才是应该考虑的措施。
我在最近的一个项目中需要从RGB像素生成Bitmap(位图)文件。Bitmap文件的头信息是用结构体描述的。 一开始写入磁盘的文件总是不对,分析发现正是因为编译器在我的结构体里填充了多余字节来满足对齐的要求。简单一个packed就解决了这个问题。
但正如前面所说,使用packed属性具有潜在的问题。如果一个结构体被packed了,尽量不要使用指向其内部成员变量的指针,除非你真的知道你在做什么。
转载:
http://blog.shengbin.me/posts/gcc-attribute-aligned-and-packed
gcc数据对齐之: howto 1.的更多相关文章
- gcc数据对齐之: howto 2.
原文链接:http://www.catb.org/esr/structure-packing/ 谁应阅读本文 本文探讨如何通过手工重新打包C结构体声明,来减小内存空间占用.你需要掌握基本的C语言知识, ...
- gcc 数据对齐之:总结篇.
通过上面的分析,总结结构体对齐规则如下: 1.数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragm ...
- [翻译] GCC 内联汇编 HOWTO
目录 GCC 内联汇编 HOWTO 原文链接与说明 1. 简介 1.1 版权许可 1.2 反馈校正 1.3 致谢 2. 概览 3. GCC 汇编语法 4. 基本内联 5. 扩展汇编 5.1 汇编程序模 ...
- 数据对齐 posix_memalign 函数详解
对齐 数 据的对齐(alignment)是指数据的地址和由硬件条件决定的内存块大小之间的关系.一个变量的地址是它大小的倍数的时候,这就叫做自然对齐 (naturally aligned).例如,对于一 ...
- C++中数据对齐问题。struct、union、enum,类继承。再谈sizeof()
首先是struct,在C++中,结构体其实和class有很大的相似了.但是有一点不同的是,struct默认是public,而class中是private. 当然,struct继承等用法也是可以的. 共 ...
- data structure alignment(数据对齐)
概述: 数据对齐指数据在计算机内存中排放和获取的方式.包含三个方面:数据对齐(data alignment).数据结构填充(data alignment).打包(packing) 如果数据是自然对齐的 ...
- gcc数据结构对齐之:why.
gcc 支持 aligned 和 packed 属性指定数据对齐,那么在了解对齐规则之前,需要解决第一个以为,我们为什么需要数据对齐?请看下图: 相信学过汇编的朋友都很熟悉这张图,这张图就是CPU与内 ...
- C++中数据对齐
大体看了看数据对齐,不知道是否正确,总结如下: struct A { char name; double dHeight; int age; }; sizeof(A) = (1+7+8+4+4) = ...
- C/C++数据对齐汇总
C/C++数据对齐汇总 这里用两句话总结数据对齐的原则: (1)对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,才干获得最好的性能: (2)如果len为结构体中长度最长的变量,s ...
随机推荐
- Python初记
------Python是一个优雅的大姐姐 我是通过<老男孩Python>学习Python,根据我手上的资源学习Python,资料不齐,但是这个是最好的,边学习边寻找有没有相同的类型. 在 ...
- hdu 4451 Dressing 衣服裤子鞋 简单容斥
Dressing Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- 614A - Link/Cut Tree 数乘
A. Link/Cut Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...
- Codeforces 1213E Two Small Strings
cf题面 中文题意 给个n,再给两个长度为2的字符串,要求构造一个长度为\(3n\)的字符串,a.b.c三个字母各n个,且构造出的字符串子串中不能出现给定的两个字符串.如果不存在这样的字符串,就输出N ...
- JVM系列2:HotSpot虚拟机对象
1.对象创建过程: ①.类加载检查:当java虚拟机遇到一条new指令时,首先会去检查该指令的参数能否在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析.初始化过,如果没 ...
- 使用Jmeter性能测试注意点
一.性能测试注意点 1. 用jmeter测试时使用BeanShell脚本获取随机参数值,会导致请求时间过长,TPS过低.应改为使用csv读取参数值,记录的TPS会更加准确. 注:进行性能测试时,应注意 ...
- 兼容ie9以下支持媒体查询和html5
<head> <!-- 让IE8/9支持媒体查询,从而兼容栅格 --> <!--[if lt IE 9]> <script src="https:/ ...
- python调用不同目录中类的终极方法
1.在需要导入别的类包中加入这两行代码 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.a ...
- linux中安装rdesktop远程访问windows服务器
下载rdesktop.此处提供一个.deb的下载包,下载地址.提取码:t020. 1.安装.终端输入 dpkg -i rdesktop_1.8.6-2_amd64.deb 安装中可能会提示错误: 缺少 ...
- elasticsearch索引大小写的问题
今天用elasticsearch创建索引时碰到一个问题,用大写创建的索引,ES前端插件可以看到用大写创建索引存入的数据 程序启动,搜索的时候,却不显示数据,索引变成了小写,导致数据无法封装传入. 在h ...