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. 微信小程序自动化测试最佳实践(附 Python 源码)

    本文为霍格沃兹测试学院测试大咖公开课<微信小程序自动化测试>图文整理精华版. 随着微信小程序的功能和生态日益完善,很多公司的产品业务形态逐渐从 App 延升到微信小程序.微信公众号等.小程 ...

  2. postman with xdebug

    Set the url with ?XDEBUG_SESSION_START=PHPSTORM and set a header Cookie: XDEBUG_SESSION=PHPSTORM

  3. Python方法oslo_service.loopingcall.LoopingCallDone代码示例

    Python方法oslo_service.loopingcall.LoopingCallDone代码示例 demo: from oslo_service import loopingcall def ...

  4. Java数据结构——2-3树

    定义2-3树是平衡的3路查找树,其中2(2-node)是指拥有两个分支的节点,3(3-node)是指拥有三个分支的节点.B-树是一种平衡的多路查找树,2-3树属于b-树,其也同样具有B-树的性质,如m ...

  5. 《Java从入门到失业》第三章:基础语法及基本程序结构(四):基本数据类型(字符编码和char型)

    3.6.4字符编码 咦?怎么好像有东西乱入了?不是讲基本数据类型么?哈哈,因为还剩下最后一个char型了,因为char型会牵涉到Unicode编码相关,因此我决定先科普一下字符集编码. 我儿子现在上小 ...

  6. myblogplus 第二期 慕舲原创 如何删除官方在你博客内设置的所有广告

    问题描述: 文章下方广告渐多了起来,这也无可厚非,原来只有小小一幅的,毕竟博客园团队很卖力,博客园首页不是在更新吗,博问也在推广(虽然解答者不多,提问者很多) 不过无疑很影响美观,那些可以让他设置,不 ...

  7. EventLoop-浏览器篇2

    最近又碰到了event loop问题,之前研究的实在是浅显(https://www.cnblogs.com/zx0423/p/12641637.html)所以今天主要讲述promise的链式调用,as ...

  8. tensorflow1.x及tensorflow2.x不同版本实现验证码识别

    近一个假期,入坑深度学习,先从能看得着的验证码识别入门.从B站看了几天的黑马程序员的“3天带你玩转python深度学习后“,一是将教程中提到的代码一一码出来:二是针对不同的tensorflow版本,结 ...

  9. 从request中获取文件流的两种方式,配置文件上传大小

    原文地址:https://blog.csdn.net/xyr05288/article/details/80692132

  10. 【免费】windows下如何生成tar.gz,一键生成tar.gz

    废话 一.实验背景 tar.gz 是Linux和Unix下面比较常用的格式,一条命令就可以把文件压缩打包成tar.gz格式,然而这种格式在windows并不多见. Linxu服务器上,tar.gz 包 ...