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报文段详解

    目录 1.TCP(Transmission Control Protocol传输控制协议)作用 2.TCP报文段详解 三.TCP报文段详解 1.TCP(Transmission Control Pro ...

  2. bytes和bytearray总结

    The core built-in types for manipulating binary data are bytes and bytearray. They are supported by ...

  3. 2018 计蒜之道-初赛 第一场 A-百度无人车

    百度一共制造了 nn 辆无人车,其中第 ii 辆车的重量为 a_i\ \mathrm{kg}ai​ kg. 由于车辆过重会增大轮胎的磨损程度,现在要给这 nn 辆车减轻重量.每将一辆车减轻 1\ \m ...

  4. [Jenkins]Job中如何传递自定义变量

    场景一: Job构建步骤间的变量传递 Jenkins提供了数十种构建方式,我们以最常用的『Execute shell』为例.有时为了使Job中的复杂的构建流程更加清晰我们配置多个构建步骤像下面这样.图 ...

  5. JavaWeb_(SSH论坛)_四、页面显示

    基于SSH框架的小型论坛项目 一.项目入门 传送门 二.框架整合 传送门 三.用户模块 传送门 四.页面显示 传送门 五.帖子模块 传送门 六.点赞模块 传送门 七.辅助模块 传送门 帖子表与回复表 ...

  6. Error:Connection activation failed: No suitable device found for this connection

    原文链接: https://blog.csdn.net/baiboya/article/details/80452822 ens33这个网卡一直无法激活,在网上找了半天,找到这个博主的文章,才解决,虽 ...

  7. C博客作业05--指针 批改总结

    1.0如题 1.1 一.评分规则 1.伪代码务必是文字+代码描述,直接反应代码,每题扣1分 2.提交列表没内容,或者太简单,每题得分0分.注意选择提交列表长的题目介绍. 3.代码格式不规范,包括命名随 ...

  8. watir安装——windows环境

    默认情况下,gem sources 都是https://rubygems.org/

  9. 有关sublime的一些使用

    习惯了vs的快捷键,用sublime的时候始终感觉不太跟手. 点击 “首选项”→“按键绑定-默认” 在新的界面中就可以更改你想要的快捷键了. 1.自动格式化对齐: 查找 "command&q ...

  10. debian安装图形界面,使用mstsc远程登录

    环境:debian 10.2 更新软件列表 apt-get update 安装最基本的gnome图形相关软件 apt install x-window-system-core gnome-core 安 ...