gcc之__attribute__简介及对齐参数介绍
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__简介及对齐参数介绍的更多相关文章
- MySQL Cluster基础知识简介以及基本参数介绍
PS:这些资料都是以前整理的,有些有可能是在网上copy别人的,但是时间长了,记不得出处了,sorry! 在MySQL Cluster环境的配置文件config.ini里面,每一类节点都有两个(或以上 ...
- Gcc ------ gcc的使用简介与命令行参数说明
gcc的使用简介与命令行参数说明 2011年06月19日 20:29:00 阅读数:10221 2011-06-19 wcdj 参考:<GNU gcc嵌入式系统开发 作者:董文军> (一) ...
- 从gcc的__attribute__((packed))聊到结构体大小的问题
公司的前辈的代码里面 结构体的花括号最后 有__attribute__((packed))字样.以前没见过,所以查了查.学习学习http://blog.sina.com.cn/s/blog_559f6 ...
- gcc的使用简介与命令行参数说明
(一) gcc的基本用法(二) 警告提示功能选项(三) 库操作选项(四) 调试选项(五) 交叉编译选项 (一) gcc的基本用法使用gcc编译器时,必须给出一系列必要的调用参数和文件名称.不同参数的先 ...
- G++ 参数介绍(转载)
g++参数介绍 From: http://www.cnblogs.com/lidan/archive/2011/05/25/2239517.html gcc and g++分别是gnu的c & ...
- 【体系结构】Oracle参数介绍
[体系结构]Oracle参数介绍 1 BLOG文档结构图 2 前言部分 2.1 导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩ ...
- Bootstrap Paginator 分页插件参数介绍及使用
Bootstrap Paginator是一款基于Bootstrap的js分页插件,功能很丰富,个人觉得这款插件已经无可挑剔了.它提供了一系列的参数用来支持用户的定制,提供了公共的方法可随时获得插件状态 ...
- Apache中 RewriteRule 规则参数介绍
Apache中 RewriteRule 规则参数介绍 摘要: Apache模块 mod_rewrite 提供了一个基于正则表达式分析器的重写引擎来实时重写URL请求.它支持每个完整规则可以拥有不限数量 ...
- 安卓图表引擎AChartEngine(五) - Dataset和Render参数介绍
下面只讲解一个Renderer和一个DataSet,更多内容参看官方文档 DefaultRenderer: void addSeriesRenderer(int index, SimpleSeries ...
随机推荐
- 浏览器自动化的一些体会4 webBrowser控件之零碎问题2
1. DocumentCompleted的多次执行问题 有的网页,会多次触发DocumentCompleted事件,由于它是异步的,不会阻塞,所以如果不恰当处理,会造成某些代码被错误地多次执行,造成意 ...
- 蒲公英 · JELLY技术周刊 Vol.18 关于 React 那些设计
蒲公英 · JELLY技术周刊 Vol.18 自 2011 年,Facebook 第一次在 News Feed 上采用了 React 框架,十年来 React 生态中很多好用的功能和工具在诸多设计思想 ...
- springboot + kafka 入门实例 入门demo
springboot + kafka 入门实例 入门demo 版本说明 springboot版本:2.3.3.RELEASE kakfa服务端版本:kafka_2.12-2.6.0.tgz zooke ...
- 用java编程在10000到99999中的数字中找到aabcc类型的数字
package com.diyo.offer; public class FindNum { public static void main(String[] args) { int count = ...
- Redis取出中文乱码问题
直接打开Redis客户端,如果存储了中文的内容,取出时会发生乱码: 解决办法很简单,打开客户端时加上 --raw,这样就可以了: 顺便说一下,-a后面跟的是密码,打码了,各位见谅!
- 【干货!!】三句话搞懂 Redis 缓存穿透、击穿、雪崩
前言 如何有效的理解并且区分 Reids 穿透.击穿和雪崩之间的区别,一直以来都挺困扰我的.特别是穿透和击穿,过一段时间就稀里糊涂的分不清了. 为了有效的帮助笔者自己,以及拥有同样烦恼的朋友们区分这三 ...
- 03.AOF持久化机制配置与工作流程
一.AOF持久化的配置 配置文件redis.conf,AOF持久化默认是关闭的,默认是打开RDB持久化 appendonly yes 二.工作流程: 打开AOF持久化机制之后,redis每次接 ...
- 《神经网络的梯度推导与代码验证》之vanilla RNN的前向传播和反向梯度推导
在本篇章,我们将专门针对vanilla RNN,也就是所谓的原始RNN这种网络结构进行前向传播介绍和反向梯度推导.更多相关内容请见<神经网络的梯度推导与代码验证>系列介绍. 注意: 本系列 ...
- 文本三剑客之sed的用法
第1章 Sed命令 1.1 sed 命令执行过程 1.2 sed介绍 sed是一种流编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(p ...
- 《Offer一箩筐》求职之前你必须知道的 4 件事!!
「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! Hi~ 这里是 ...