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.的更多相关文章

  1. gcc数据对齐之: howto 2.

    原文链接:http://www.catb.org/esr/structure-packing/ 谁应阅读本文 本文探讨如何通过手工重新打包C结构体声明,来减小内存空间占用.你需要掌握基本的C语言知识, ...

  2. gcc 数据对齐之:总结篇.

    通过上面的分析,总结结构体对齐规则如下: 1.数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragm ...

  3. [翻译] GCC 内联汇编 HOWTO

    目录 GCC 内联汇编 HOWTO 原文链接与说明 1. 简介 1.1 版权许可 1.2 反馈校正 1.3 致谢 2. 概览 3. GCC 汇编语法 4. 基本内联 5. 扩展汇编 5.1 汇编程序模 ...

  4. 数据对齐 posix_memalign 函数详解

    对齐 数 据的对齐(alignment)是指数据的地址和由硬件条件决定的内存块大小之间的关系.一个变量的地址是它大小的倍数的时候,这就叫做自然对齐 (naturally aligned).例如,对于一 ...

  5. C++中数据对齐问题。struct、union、enum,类继承。再谈sizeof()

    首先是struct,在C++中,结构体其实和class有很大的相似了.但是有一点不同的是,struct默认是public,而class中是private. 当然,struct继承等用法也是可以的. 共 ...

  6. data structure alignment(数据对齐)

    概述: 数据对齐指数据在计算机内存中排放和获取的方式.包含三个方面:数据对齐(data alignment).数据结构填充(data alignment).打包(packing) 如果数据是自然对齐的 ...

  7. gcc数据结构对齐之:why.

    gcc 支持 aligned 和 packed 属性指定数据对齐,那么在了解对齐规则之前,需要解决第一个以为,我们为什么需要数据对齐?请看下图: 相信学过汇编的朋友都很熟悉这张图,这张图就是CPU与内 ...

  8. C++中数据对齐

    大体看了看数据对齐,不知道是否正确,总结如下: struct A { char name; double dHeight; int age; }; sizeof(A) = (1+7+8+4+4) =  ...

  9. C/C++数据对齐汇总

     C/C++数据对齐汇总  这里用两句话总结数据对齐的原则: (1)对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,才干获得最好的性能: (2)如果len为结构体中长度最长的变量,s ...

随机推荐

  1. 计算机网络(七),TCP与UDP的区别

    七.TCP与UDP的区别 1.面向连接VS无连接 TCP面向连接而UDP面向无连接的,TCP是和单对单传送数据,UDP适合多波发布 2.可靠性 TCP利用握手,确认,重传机制提供了可靠性保证,UDP可 ...

  2. 网页“console”输出图文信息

    http://www.monmonkey.com/javascript/jiben2.html 参考以上链接中的转义字符使用. http://www.cnblogs.com/Wayou/p/chrom ...

  3. 「WC 2007」剪刀石头布

    题目链接 戳我 \(Solution\) 直接求很明显不太好求,于是考虑不构成剪刀石头布的情况. 我们现在假设一个人\(i\)赢了\(x\)场,那么就会有\(\frac{x*(x-1)}{2}\) 我 ...

  4. hdfs、zookeepeer之HA模式

    HA简介 1.所谓HA,即高可用(high available) 2.消除单点故障,避免集群瘫痪,hdfs中namenode保存了整个集群的元数据,如果namenode所在机器宕机,则整个集群瘫痪,H ...

  5. 全面解读PHP-数据结构

    一.常见数据结构 1.Array 数组 最简单且应用最广泛的数据结构之一 特性:使用连续的内存来存储,数组中的所有元素必须是相同的类型或类型的衍生(同质数据结构),元素可以通过下标直接访问. 2.Li ...

  6. 四、日志输出Reporter.log

    一.Reporter.log import org.testng.Reporter; public class TestLog { public static void main(String[] a ...

  7. 问题:unknown error: call function result missing 'value' 解决方法

    问题:unknown error: call function result missing 'value' 页面也没有 填充信息 原因是:安装与chrome和对应的chromedriver版本问题 ...

  8. Jmeter(六)事务

    事务是性能测试之必不可少的关注点, Jmeter默认把每一个请求都统计成了一个事务, 但有时候我们根据业务需求, 会把多个操作统计成一个事务, Jmeter当然也考虑到了这个需求, 因此我们可以通过逻 ...

  9. Struts2-Ajax整合之纯JavaScript版本

    1.Ajax的作用:能够在不重新加载页面的情况下,用异步的方式与后台服务器进行数据交互 2.Struts2-Json的jar包(包含阿里巴巴自己的jar包) commons-beanutils-1.7 ...

  10. 【汇总】Windows linux 敏感目录 路径汇总

    日期:2019-08-02 10:53:52 更新:2019-08-19 15:48:01 作者:Bay0net 介绍:中间件.套件等等敏感信息,做个记录. 0x01. 基本信息 遇到文件包含.任意文 ...