原创 GUN C attribute的一些常用方法

2012-8-22 10:58 829 7 7 分类: MCU/ 嵌入式

在学习一些uboot、linux内核源码的时候,会经常看到有关__attribute__的相关使用,这个__attribute__机制是GUN C的一大特色,但是不被初学者所知。这个__attribute__可以设置函数属性(Function Attribute)、变量属性(VariableAttribute)和类型属性(Type Attribute)。

__attribute__语法格式如下:

__attribute__ ((attribute-list))

attribute-list是一个可能用逗号分隔开的一些空属性列表,每一个属性有如下一种格式:

  • 空的属性,空的属性会被忽略。
  • 就只有一个描述属性的单词。
  • 一个描述属性的单词后面还带有括号,括号中还有参数。

 

下面分别从__attribute__对函数、变量、类型修饰分别说一下几个人常用的属性:

一、函数属性(Function Attribute)

         函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。__attribute__机制也很容易同非GNU应用程序做到兼容之功效。GNU CC需要使用–Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。下面介绍几个常见的属性参数。

format,format格式如下:

format(archetype, string-index, first-to-check)

format属性告诉编译器,按照printf, scanf, strftime或strfmon的参数表格式规则对该函数的参数进行检查。“archetype”指定按哪种风格做类型检查;“string-index”指定传入函数的第几个参数是格式化字符串;“first-to-check”指定从函数的第几个参数开始按上述规则进行检查。请看如下的例子:

extern int my_printf (void *my_object, const char *my_format, ...) __attribute__ ((format (printf, 2, 3)));

以上这个例子,格式字符串是my_print这个函数的第二个参数,而参数检查的开始位置是在第三个参数的位置,所以对format这个属性正确的参数填写是2和3。

通常情况下,GNU CC编译器,在使用了-Wformat时候就对标准库中类似于printf、fprintf、sprintf等函数做格式检查。

noreturn

如果你想在自己的程序当中定义一些决对不是会有返回值的函数时,你可以使用这个属性,来告诉编译器这个就是事实。请看如下例子:

void fatal () __attribute__ ((noreturn));       
void  fatal (/* ...*/)
{
   /* ...*/ /* Print error message.*/ /* ...*/
   exit (1);
}
     
     注意:这里只列举了这两个属性,还有其它的很的属性,如果对这个有兴趣的话,不防去访问如下这个网址:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html#Function-Attributes
     当然对以上的属性可以一起使用,使用如下:

extern int

my_printf (void *my_object, const char *my_format, ...)

__attribute__((noreturn))

                 __attribute__ ((format (printf, 2, 3)));

     也可以使用如下写法:

     extern int

my_printf (void *my_object, const char *my_format, ...)

                       __attribute__ ((noreturn, format (printf, 2, 3)));


二、变量属性(Variable Attribute)

__attribute__允许对变量带或者结构体中的成员使用特定的属性来进行修饰,一些属性可以用来修饰般的变量,而有的变量只可以用在特定的目标系统中。以下是对变量属性修饰的几个属性进行说明:

aligned

这个属性指定了变量或者结构体成员的最小对齐字节数。看如下例子:

int x __attribute__ ((aligned (16))) = 0;
编译器将以16字节对齐的方式为这个变量分配16个字节的存储空间。该属性也可以用在结构体成员上,如下:
struct foo { int x[2] __attribute__ ((aligned (8))); };

如上例子所示,你可以指定编译器在为一个变量或者结构体成员在分配内存空间时候按照你自己所指定的字节对齐数来进行分配内在空间。同样,你也可以不指定对齐因子,那么编译器将依据你的目标机器情况使用最大最有益的对齐方式。请看如下例子:

short array[3] __attribute__ ((aligned));

如果你不指定对齐因子,那么编译器会自动的按照该变量或者结构体成员的数据类型在该目标平台上的最大对齐字节数来进行内在分配。这个aligned属性只可以增加对齐的字节数,而packed属性可以减少对齐的字节数,有关packed在下面讲到。

 

说明:aligned属性的有效性会受到链接器固有的限制性所限制。在许多的系统中,链接器对最大的对齐字节数有一个固定的最大值限定。如果你的链接器限定了最大的对齐字节数为8个字节,而你为某个变量或者结构体成员做用了aligned(16)这个属性,此时__attribute__也只做8个字节对齐来处理。

packed

packed这个属性可以使变量或者结构体成员使用最小的字节数对齐:一个字节对齐,也可以指定位域为一个一个bit对齐,除非你使用了aligned这个属性指定了一个很大的值。如下有一个有关packed使用的例子:

struct foo
       {
    char a;
    int x[2] __attribute__ ((packed));
};
对以上这个结构体进行如下:  sizeof(struct stu)得到的结果应该是9。
对于有关变量的其它一些属性,在如下链接当中可以查看详细:
http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes

三、类型属性(Type Attribute)

当你在定义像结构体和联合体类型的时候,可以使用__attribute__指定一些特定的属性为你自己定义结构体和联合体。一般情况下有几个属性来修饰数据类型,以下就来介绍几种:

aligned

这个属性指定了这个变量的类型最小的对齐字节数,有如下例子:

struct S { short f[3]; } __attribute__ ((aligned (8)));
typedef int more_aligned_int __attribute__ ((aligned (8)));

以上声明强制编译器确保为这struct S或者more_aligned_int类型的变量在分配内存空间时采用8字节对齐的方式。

如上例子所示,你可以指定编译器在为一个结构体类型或者联合体类型的变量在分配内存空间时候按照你自己所指定的字节对齐数来进行分配内在空间。同样,你也可以不指定对齐因子,那么编译器将依据你的目标机器情况使用最大最有益的对齐方式。

packed

使用该属性对struct或者union类型进行定义,设定其类型的每一个变量的内存约束。当用在enum类型定义时,暗示了应该使用最小完整的类型。

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

 struct my_unpacked_struct

{

  char c;
  int i;
};
          
struct my_packed_struct __attribute__ ((packed))
{
char c;
         int  i;
struct my_unpacked_struct s;
};

还有其它的一些属性,可以在如下的网址中有详细的描述:

http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes

------分隔线----------------------------

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条