GNU C的一大特色就是__attribute__机制。__attribute__机制可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。

  __attribute__语法格式为:__attribute__((attribute-list))。

__attribute__对结构体(struct)或共用体(union)进行属性设置:

  大致有六个参数值可以被设定,即:aligned,packed,transparent_union,deprecated和may_alias。

  在使用__attribute__参数时,你也可以在参数的前后都加上“__”(两个下划线),例如,使用__aligned__而不是aligned,这样,你就可以在相应的头文件里使用它而不需要关心头文件里是否有重名的宏定义。

 

  1. aligned(alignment):

    设定对齐的格式(以字节为单位),例如:

struct S {
short b[];
}__attribute__((aligned ()));
typedef int int32_t __attribute__((aligned(8)));
/*
* 该声明将强制编译器确保(尽可能)变量类型为structS或者int32_t的变量在分配空间时采用8字节对齐方式。
*/

  如上所述,你可以手动指定对齐的格式,同样,你也可以使用默认的对齐方式。如果aligned后面不指定数值,那么编译器将依据你的目标机器情况使用最大最有益的对齐方式。例如:

struct S {
short b[];
} __attribute__((aligned)); // 使用默认对齐方式,依据目标机器,使用最大最有益的对齐方式
#include <stdio.h>

struct S1 {
short b[];
}; struct S2 {
short b[];
} __attribute__((aligned())); struct S3 {
short b[];
} __attribute__((aligned())); struct S4 {
short b[];
} __attribute__((aligned())); struct S5 {
short b[];
} __attribute__((aligned())); struct S6 {
short b[];
} __attribute__((aligned)); int main(int argc, char** argv)
{
printf("sizeof(struct S1) = %ld\n", sizeof(struct S1));
printf("sizeof(struct S2) = %ld\n", sizeof(struct S2));
printf("sizeof(struct S3) = %ld\n", sizeof(struct S3));
printf("sizeof(struct S4) = %ld\n", sizeof(struct S4));
printf("sizeof(struct S5) = %ld\n", sizeof(struct S5));
printf("sizeof(struct S6) = %ld\n", sizeof(struct S6)); return ;
}
/*
* 输出结果:
* sizeof(struct S1) = 6
* sizeof(struct S2) = 8
* sizeof(struct S3) = 16
* sizeof(struct S4) = 32
* sizeof(struct S5) = 64
* sizeof(struct S6) = 16
*/

  注意:__attribute__属性的效力与你的链接器有关,如果你的链接器最大只支持16字节对齐,那么你此时定义32字节对齐也无济于事。

#include <stdio.h>

struct A {
int a;
char b;
short c;
} aa; struct AP {
int a;
char b;
short c;
} __attribute__((aligned())) ap; struct B {
char a;
int b;
short c;
} bb; struct BP {
char a;
int b;
short c;
} __attribute__((aligned())) bp; struct C {
int a;
char b;
struct AP px;
short c;
} cc; struct CP1 {
int a;
char b;
struct AP px;
short c;
} __attribute__((aligned())) cp1; struct CP2 {
int a;
char b;
struct AP px;
short c;
} __attribute__((aligned())) cp2; int main(int argc, char** argv)
{
printf("sizeof(aa) = %lu, sizeof(ap) = %lu\n", sizeof(aa), sizeof(ap));
printf("sizeof(bb) = %lu, sizeof(bp) = %lu\n", sizeof(bb), sizeof(bp));
printf("sizeof(cc) = %lu, sizeof(cp1) = %lu\n", sizeof(cc), sizeof(cp1));
printf("sizeof(cc) = %lu, sizeof(cp2) = %lu\n", sizeof(cc), sizeof(cp2)); return ;
}
/*
* 输出结果:
* sizeof(aa) = 8, sizeof(ap) = 16
* sizeof(bb) = 12, sizeof(bp) = 12
* sizeof(cc) = 48, sizeof(cp1) = 48
* sizeof(cc) = 48, sizeof(cp2) = 48
*/

关于内存对齐:(其中的#pragma pack()在gcc中很少见,具体用法需确认)

  ① 什么是内存对齐?

    不同类型的数据在内存中按照一定的规则排列;而不是顺序的一个接一个的排放,这就是对齐。

#include <stdio.h>

struct Test1 {
char c1;
short s;
char c2;
int i;
}; struct Test2 {
char c1;
char c2;
short s;
int i;
}; int main(int argc, char** argv)
{
printf("sizeof(struct Test1) = %lu\n", sizeof(struct Test1));
printf("sizeof(struct Test2) = %lu\n", sizeof(struct Test2)); return ;
} /* 输出结果
* sizeof(struct Test1) = 12
* sizeof(struct Test2) = 8
*/

  ②为什么需要内存对齐?

    • CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是1、2、4、8、16字节
    • 当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
    • 某些硬件平台只能从规定的地址处取某些特定类型的数据,否则则抛出硬件异常      

  #pragma pack能够改变编译器的默认对齐方式

#include <stdio.h>

#pragma pack(2)
struct Test1 {
char c1;
short s;
char c2;
int i;
};
#pragma pack() #pragma pack(4)
struct Test2 {
char c1;
char c2;
short s;
int i;
};
#pragma pack() int main(int argc, char** argv)
{
printf("sizeof(struct Test1) = %lu\n", sizeof(struct Test1));
printf("sizeof(struct Test2) = %lu\n", sizeof(struct Test2)); return ;
} /*
* 输出结果:
* sizeof(struct Test1) = 10
* sizeof(struct Test2) = 8
*/
  • struct 占用的内存大小

    • 第一个成员起始于0偏移处
    • 每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐
      • 偏移地址和成员占用大小均需对齐
      • 结构体成员的对齐参数为其所有成员使用的对其参数的最大值    
    • 结构体的总长度必须为所有对其参数的整数倍      
#include <stdio.h>

#pragma pack(8)

struct S1 {
short a;
long b;
}; struct S2 {
char c;
struct S1 d;
double e;
}; #pragma pack() int main()
{
struct S2 s2; printf("sizeof(struct S1) = %lu\n", sizeof(struct S1));
printf("sizeof(struct S2) = %lu\n", sizeof(struct S2)); printf("%d\n", sizeof(long)); printf("%d\n", (int)&(s2.d) - (int)&(s2.c)); return ;
} /*
* 输出结果:
* sizeof(struct S1) = 16
* sizeof(struct S2) = 32
* 8
* 8
*/

  aligned属性被设置的对象占用更多的空间,相反的,使用packed可以减小对象占用的空间。

  2. packed:

    使用该属性对struct或union类型进行定义,设定其类型的每一个变量的内存约束。当用在enum类型定义时,暗示了应该使用最小完整的类型(it indicates that the smallest integral type should be used)。

#include <stdio.h>

struct unpacked_struct {
char c;
int i;
}; struct packed_struct_1 {
char c;
int i;
} __attribute__((__packed__)); struct packed_struct_2 {
char c;
int i;
struct unpacked_struct us;
} __attribute__((__packed__)); int main(int argc, char** argv)
{
printf("sizeof(struct unpacked_struct) = %lu\n", sizeof(struct unpacked_struct));
printf("sizeof(struct packed_struct_1) = %lu\n", sizeof(struct packed_struct_1));
printf("sizeof(struct packed_struct_2) = %lu\n", sizeof(struct packed_struct_2)); return ;
} /*
* 输出:
* sizeof(struct unpacked_struct) = 8
* sizeof(struct packed_struct_1) = 5
* sizeof(struct packed_struct_2) = 13
*/

参考文章:

http://www.cnblogs.com/astwish/p/3460618.html

gcc之__attribute__简介及对齐参数介绍的更多相关文章

  1. MySQL Cluster基础知识简介以及基本参数介绍

    PS:这些资料都是以前整理的,有些有可能是在网上copy别人的,但是时间长了,记不得出处了,sorry! 在MySQL Cluster环境的配置文件config.ini里面,每一类节点都有两个(或以上 ...

  2. Gcc ------ gcc的使用简介与命令行参数说明

    gcc的使用简介与命令行参数说明 2011年06月19日 20:29:00 阅读数:10221 2011-06-19 wcdj 参考:<GNU gcc嵌入式系统开发 作者:董文军> (一) ...

  3. 从gcc的__attribute__((packed))聊到结构体大小的问题

    公司的前辈的代码里面 结构体的花括号最后 有__attribute__((packed))字样.以前没见过,所以查了查.学习学习http://blog.sina.com.cn/s/blog_559f6 ...

  4. gcc的使用简介与命令行参数说明

    (一) gcc的基本用法(二) 警告提示功能选项(三) 库操作选项(四) 调试选项(五) 交叉编译选项 (一) gcc的基本用法使用gcc编译器时,必须给出一系列必要的调用参数和文件名称.不同参数的先 ...

  5. G++ 参数介绍(转载)

    g++参数介绍 From: http://www.cnblogs.com/lidan/archive/2011/05/25/2239517.html gcc and g++分别是gnu的c & ...

  6. 【体系结构】Oracle参数介绍

    [体系结构]Oracle参数介绍 1  BLOG文档结构图 2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩ ...

  7. Bootstrap Paginator 分页插件参数介绍及使用

    Bootstrap Paginator是一款基于Bootstrap的js分页插件,功能很丰富,个人觉得这款插件已经无可挑剔了.它提供了一系列的参数用来支持用户的定制,提供了公共的方法可随时获得插件状态 ...

  8. Apache中 RewriteRule 规则参数介绍

    Apache中 RewriteRule 规则参数介绍 摘要: Apache模块 mod_rewrite 提供了一个基于正则表达式分析器的重写引擎来实时重写URL请求.它支持每个完整规则可以拥有不限数量 ...

  9. 安卓图表引擎AChartEngine(五) - Dataset和Render参数介绍

    下面只讲解一个Renderer和一个DataSet,更多内容参看官方文档 DefaultRenderer: void addSeriesRenderer(int index, SimpleSeries ...

随机推荐

  1. 5年Java程序员,五面蚂蚁险拿offer定级P7,大厂面试不过如此?

    当时面试能记下的就这些了,可能不太全请见谅: 一面 1.HashMap和ConcurrentHashMap: 2.再谈谈一致hash算法? 3.乐观锁还有悲观锁: 4.可重入锁和Synchronize ...

  2. Nginx的Gzip功能

    什么是HTTP压缩 有时候客户端和服务器之间会传输比较大的报文数据,这时候就占用较大的网络带宽和时长.为了节省带宽,加速报文的响应速速,可以将传输的报文数据先进行压缩,然后再进行传输. HTTP支持多 ...

  3. 前端vue2-org-tree实现精美组织架构图

    最近遇到开发组织架构的需求,与以往开发的组织架构不同,不光要展示人名,还要显示职务(或者子公司名称).对应的头像等,并且要考虑,如果用户未上传头像,需使用默认头像(男.女.中性),(⊙o⊙)…要尊重尊 ...

  4. 《Java从入门到失业》第一章:计算机基础知识(二):计算机组成及基本原理

    1.2计算机组成及基本原理 1.2.1硬件组成 这里说的计算机主要指微型计算机,俗称电脑.一般我们见到的有台式机.笔记本等,另外智能手机.平板也算.有了一台计算机,我们就能做很多事情了,比如我在写这篇 ...

  5. Linux命令--vi/vim复制一行,粘贴

    在光标的位置按“yy”,复制当前行: 然后再光标的行按“p”,粘贴到下一行,原来的往下顺移

  6. kvm-virtualization – 删除“孤儿”libvirt快照

    原文链接:https://codeday.me/bug/20181110/371346.html 创建快照: virsh snapshot-create-as --domain prod snap - ...

  7. xfs文件系统修复方法

    1. 前言首先尝试mount和umount文件系统,以便重放日志,修复文件系统,如果不行,再进行如下操作.fdisk -l 查看硬盘分区情况mount -l 查看文件系统挂载情况df -h 查看文件系 ...

  8. 使用grub2引导进入Linux或Window系统

    很多人在一通烂搞之后把自己的grub搞崩了(比如我当时手贱删除了boot分区)虽然后来又装了grub,但是进入grub后还是没有引导,只有一个孤零零的命令行界面 这时候应该怎么办呢?首先当然是想进入系 ...

  9. 【独家】React Native 版本升级指南

    前言 React Native 作为一款跨端框架,有一个最让人头疼的问题,那就是版本更新.尤其是遇到大版本更新,JavaScript.iOS 和 Android 三端的配置构建文件都有非常大的变动,有 ...

  10. React_TODOList 数据增删改查

    ①.功能代码实现: 添加数据 查询数据,展示 删除数据 修改数据 ②.数据持久化操作 localStorage.setItem('key',value) var value = localStorag ...