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. MySQL设置传输包大小

    MySQL执行插入或更新时, 当数据量过大时, 可能由于"max_allowed_packet"参数的限制导致执行失败.此时, 可以重新设置该参数的值. "max_all ...

  2. 笔试算法稳了,GitHub 50k Star《labuladong的算法小抄》

    秋招算法有救了!!! 前不久在 GitHub 出现了一个手把手带你刷 LeetCode 的项目:fucking-algorithm. 该项目此前在 GitHub 开源后,连续多次霸榜 GitHub T ...

  3. YApi——手摸手,带你在Win10环境下安装YApi可视化接口管理平台

    手摸手,带你在Win10环境下安装YApi可视化接口管理平台 YApi YApi 是高效.易用.功能强大的 api 管理平台,旨在为开发.产品.测试人员提供更优雅的接口管理服务.可以帮助开发者轻松创建 ...

  4. java反序列化——XMLDecoder反序列化漏洞

    本文首发于“合天智汇”公众号 作者:Fortheone 前言 最近学习java反序列化学到了weblogic部分,weblogic之前的两个反序列化漏洞不涉及T3协议之类的,只是涉及到了XMLDeco ...

  5. 【翻译】Promises/A+规范

    目录 介绍 译文 1. 术语(Terminology) 2. 要求(Requirements) 2.1 Promise状态 2.2 then方法 2.3 Promise解析程序 3. 注释 3.1 p ...

  6. webpack 热替换

    一. 使用express.js搭建一个简易服务器demo地址,热替换的 先看包 // 清除重复的文件 "clean-webpack-plugin" // css加载器 " ...

  7. Invalid credentials for 'https://repo.magento.com/packages.json'

    Use your public key as username and private key as password from your magento connect account You ca ...

  8. badger 一个高性能的LSM K/V store

    原文:https://colobu.com/2017/10/11/badger-a-performant-k-v-store/ github地址:https://github.com/dgraph-i ...

  9. python 递归删除空文件夹

    Python如何递归删除空文件夹 1.Python如何递归删除空文件夹,这个问题很常见.但大多数人的解决办法都是自己实现递归函数解决这个问题,其实根本不用那么麻烦.Python中的os.walk提供了 ...

  10. mysql中的函数总结

    mysql中常用日期时间函数 MySQL服务器中的三种时区设置: ①系统时区---保存在系统变量system_time_zone ②服务器时区---保存在全局系统变量global.time_zone ...