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. Windows下 Navicat Premium 15安装教程(图文,含注册)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://www.cnblogs.com/zhangzhicheng1996/ ...

  2. vue自定义可输入的选择框组件

    vue自定义可输入的选择框组件 props: 属性 说明 类型 默认值 selectDataList 下拉框中的内容 Array 空数组([]) value 输入框中的内容 String 空字符串(& ...

  3. GUAVA-ListenableFuture实现回调

    随着软件开发的不断进步,在实际的开发应用中,可能一次请求需要查询若干次数据库或者调用若干次第三方,按照传统的串行执行的话,会大大增加响应时间,无法满足业务需求,更无法满足用户迫切需要响应迅速的愿望.对 ...

  4. EXCEL 中数据 批量 填充进 word 中

    工具:Python3.7 需求描述:将EXCEL中 第二行 数据 填在 word 对应位置上,然后保存为 "姓名+任务.docx"文件. 再将EXCEL中 第三行 数据 填在 wo ...

  5. 为什么 max() 应该写成 b < a ? a : b 呢?

    在 < C++ Templates 2nd Edition >Chapter 1 中,作者将 max() 模板定义如下: template <typename T> T max ...

  6. 【接口自动化】Python+Requests接口自动化测试框架搭建【二】

    接续前文,在上篇博客中我们编写了demo.py代码,里面代码过多冗余,更新代码: #!/usr/bin/env python # coding=utf-8 import requests class ...

  7. k8s 辨析 port、NodePort、targetPort、containerPort 区别

    刚接触 k8s 涉及到端口到内容较多,容易混淆,这里整理如下: 目录 nodePort port targetPort containerPort 参考文章 nodePort nodePort 提供了 ...

  8. chrome浏览器截图

    1.F12 打开开发者工具台 2.ctrl + shift + p,弹出搜索框之后输入: full 3.选中Mobile-- Capture fullsize screenshot ,成功保存图片.

  9. Java 8新的时间日期库,这二十个案例看完你还学不会算我的!!!

    Java对日期,日历及时间的处理一直以来都饱受诟病,尤其是它决定将java.util.Date定义为可修改的以及将SimpleDateFormat实现成非线程安全的.看来Java已经意识到需要为时间及 ...

  10. JS手写call、bind、apply

    call方法的实现 Function.prototype.MyCall = function(content,...args){ const self = content || window; con ...