C语言--attributed用法实例

总结于:https://blog.csdn.net/weixin_37921201/article/details/119429391


GNU C 的一大特色就是__attribute__ 机制。

关键字__attribute__可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute )。也可以对结构体(struct )或共用体(union )进行属性设置。大致有六个参数值可以被设定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias 。

__attribute__书写特征是:__attribute__ 前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__ 参数。

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

其位置约束为:放于声明的尾部“ ;” 之前。

储备知识: 字节对齐规则

1、64位WIN10系统下,使用MinGW GCC编译C语言工程得到:

sizeof(char)=1, sizeof(short)=2, sizeof(int)=4,sizeof(double)=8,sizeof(float)=4,sizeof(long)=4,sizeof(long long)=8

2、结构体对齐 规则

struct y
{
	//偏移地址,占用字节
    int a;//0,4bytes
    char b;//4,1bytes
    char c;//5,1bytes
    char d;//6,1bytes
    short e;//7 no; 8,2bytes
    int f;//10 no; 12,4bytes
    char g;//16,1bytes
    double h;//17 no; 24,8bytes
    char i;//32,1bytes
}yy;//>=33; 8*N=40bytes

打印结构体信息:
sizeof(yy)=40 , yy=0x004079c0,
yy.a=0x004079c0, yy.b=0x004079c4,yy.c=0x004079c5,yy.d=0x004079c6,yy.e=0x004079c8,
yy.f=0x004079cc, yy.g=0x004079d0,yy.h=0x004079d8,yy.i=0x004079e0

规则1:结构体成员,起始地址必须为自身size的整数倍,占用尺寸为自身size。
比如yy.e,自身size为2,它之前的空闲地址为0x004079c7,由于起始地址必须为2的整数倍,所以yy.e=0x004079c8。同理的还有yy.f,yy.h。

规则2:结构体占用size,看所有结构体成员中,最大的对齐参数,假设为N,结构体占用size就必须为N的整数倍。
上述例子中float的size最大,8字节。那么yy结构体占用size就不是yy.i的结束地址33bytes,而是8*5=40bytes。

aligned (alignment)

该属性设定一个指定大小的对齐格式(以字节 为单位),例如:

struct S {

short b[3];

} __attribute__ ((aligned (8)));

typedef int int32_t __attribute__ ((aligned (8)));

该声明将强制编译器确保(尽它所能)变量类 型为struct S 或者int32_t 的变量在分配空间时采用8 字节对齐方式。

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

struct S {

short b[3];

} attribute ((aligned));

这里,如果sizeof (short )的大小为2 (byte ),那么,S 的大小就为6 。取一个2 的次方值,使得该值大于等于6 ,则该值为8 ,所以编译器将设置S 类型的对齐方式为8 字节。

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

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

packed

下面的例子中,packed_struct 类型的变量数组中的值将会紧紧的靠在一起,但内部的成员变量s 不会被“pack” ,如果希望内部的成员变量也被packed 的话,unpacked-struct 也需要使用packed 进行相应的约束。

struct unpacked_struct
{
      char c;//不会pack
      int i;//不会pack
}unpacks;

struct  __attribute__ ((__packed__)) packed_struct
{
     char c;//pack
     int  i;//pack
     struct unpacked_struct s;//pack
     double d;//pack
} packs;

打印信息:
sizeof(struct unpacked_struct)=8, sizeof(struct packed_struct)=21
packs=4079f0,packs.c=4079f0, packs.i=4079f1,packs.s=4079f5,packs.d=4079fd

1、可以看到,unpacked_struct结构体是按照字节对齐规则对齐的;
2、被packed修饰过的packed_struct结构体,不进行对齐,变量多大就占用多大内存。所以它的size为(1+4+8+8)=21bytes 。

//以下位置中,只有2和3位置加入 __attribute__ ((__packed__)) 有效
① struct ② packed_struct 
{
     char c;
     int  i;
     double d;
}  ③ packs ④;

weak

有强引用(无weak属性)优先编译强引用,没有则编译器弱引用(有weak属性)函数,避免编译出错。

__attribute__ ((weak)) int32_t  getTime()
{
    OSA_WARN(" weak\n");
    return -1;
}

int32_t  getTime()
{
    OSA_WARN(" strong\n");
    return -1;
}

section

提到section,就得说RO RI ZI了,在ARM编译器编译之后,代码被划分为不同的段,RO
Section(ReadOnly)中存放代码段和常量,RW Section(ReadWrite)中存放可读写静态变量和全局变量,ZI Section(ZeroInit)是存放在RW段中初始化为0的变量。

attribute((section(“section_name”))),其作用是将作用的函数或数据放入指定名为"section_name"对应的段中。

编译时为变量指定段名

const int descriptor[3] __attribute__ ((section ("descr"))) = { 1,2,3 };

long long rw[10] __attribute__ ((section ("RW")));

编译时为函数指定段名

void Function_Attributes_section_0 (void) __attribute__ ((section ("new_section")));
void Function_Attributes_section_0 (void)
{
    static int aStatic =0;
    aStatic++;
}

__attribute__ ((section ("bar"))) int f3()
{
   return 1;
}

at

绝对定位,可以把变量或函数绝对定位到Flash中,或者定位到RAM。

定位到flash中,一般用于固化的信息,如出厂设置的参数,上位机配置的参数,ID卡的ID号,flash标记等等

const u16 gFlashDefValue[8] attribute((at(0x0800F000))) = {0x1111,0x1111,0x1111,0x0111,0x0111,0x0111};//定位在flash中,其他flash补充为00

posted @ 2023-01-30 12:10  solonj  阅读(99)  评论(0编辑  收藏  举报