GNU C 的一大特色就是__attribute__ 机制。__attribute__ 可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。

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

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

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

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

下面介绍几个常见的属性参数:

__attribute__ format  该属性可以给被声明的函数加上类似printf或者scanf的特征,它可以使编译器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。该功能十分有用,尤其是处理一些很难发现的bug。

format的语法格式为:format (archetype, string-index, first-to-check)

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

具体使用格式如下:

__attribute__((format(printf,m,n)))

__attribute__((format(scanf,m,n)))

其中参数m与n的含义为:

m:第几个参数为格式化字符串(format string);

n:参数集合中的第一个,即参数“…”里的第一个参数在函数参数总数排在第几.这里需要注意,有时函数参数里还有“隐身”的,如C++的类成员函数的第一个参数实际上是"隐身"的"this"指针;

在使用上,__attribute__((format(printf,m,n)))是常用的,而另一种却很少见到。

下面举例说明,其中myprint为自己定义的一个带有可变参数的函数,其功能类似于printf:

// m = 1, n = 2...如果在这里myprint()为类成员函数,则gcc编译后会提示"format argument is not a pointer"的警告
extern void myprint(const char *format,...) __attribute__((format(printf,1,2)));

// m = 2, n = 3
extern void myprint(short num,const char *format,...) __attribute__((format(printf,2,3)));

最经典的应用可以去看linux源码里的函数device_create(...)和class_device_create(...), 做linux驱动开发的小伙伴应该对这两个函数不陌生.

__attribute__ noreturn  该属性通知编译器函数从不返回值。当遇到函数需要返回值却还没运行到返回值处就已退出来的情况,该属性可以避免出现错误信息。

C库函数中的abort()和exit()的声明格式就采用了这种格式

extern void exit(int)  __attribute__((noreturn));
extern void abort(void)  __attribute__((noreturn));
例如下面这段代码:
extern void myexit(int);
int testFunc(void)
{
    printf("-- Enter %s --", __func__);

    myexit(0);

    // 其实函数运行不到这里
    printf("-- Exit %s --", __func__);
}

void myexit(int i)
{
    exit(i);
}

编译时会报"control reaches end of non-void function"的警告, 但若将"extern void myexit(int);"改为"extern void myexit(int) __attribute__((noreturn));" 就不会再报警告了.

__attribute__ constructor/destructor  若函数被设定为constructor属性,则该函数会在 main()函数执行之前被自动的执行。类似的,若函数被设定为destructor属性,则该函数会在main()函数执行之后或者exit()被调用后被自动的执行。拥有此类属性的函数经常隐式的用在程序的初始化数据方面。

这两个属性还没有在面向对象C中实现。

__attribute__((constructor)) void before_main() {
   printf("--- %s\n", __func__);
}

__attribute__((destructor)) void after_main() {
   printf("--- %s\n", __func__);
}

int main(int argc, char **argv) {
   printf("--- %s\n", __func__);

   exit(0);

   printf("--- %s, exit ?\n", __func__);

   return 0;
}

执行结果为:

--- before_main
--- main
--- after_main
------------------------------------ Good good study, day day up! ----------------------------------:)
 
分类: C/C++

__attribute__ 机制详解(一)的更多相关文章

  1. __attribute__ 机制详解

    GNU C 的一大特色就是__attribute__ 机制.__attribute__ 可以设置函数属性(Function Attribute).变量属性(Variable Attribute)和类型 ...

  2. 从mixin到new和prototype:Javascript原型机制详解

    从mixin到new和prototype:Javascript原型机制详解   这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...

  3. 浏览器 HTTP 协议缓存机制详解

    最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag, ...

  4. JVM的垃圾回收机制详解和调优

    JVM的垃圾回收机制详解和调优 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都 ...

  5. ThreadPoolExecutor运转机制详解

    ThreadPoolExecutor运转机制详解 - 走向架构师之路 - 博客频道 - CSDN.NET 最近发现几起对ThreadPoolExecutor的误用,其中包括自己,发现都是因为没有仔细看 ...

  6. Linux 内存机制详解宝典

    Linux 内存机制详解宝典 在linux的内存分配机制中,优先使用物理内存,当物理内存还有空闲时(还够用),不会释放其占用内存,就算占用内存的程序已经被关闭了,该程序所占用的内存用来做缓存使用,对于 ...

  7. PHP的垃圾回收机制详解

    原文:PHP的垃圾回收机制详解 最近由于使用php编写了一个脚本,模拟实现了一个守护进程,因此需要深入理解php中的垃圾回收机制.本文参考了PHP手册. 在理解PHP垃圾回收机制(GC)之前,先了解一 ...

  8. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  9. Android事件分发机制详解

    事件分发机制详解 一.基础知识介绍 1.经常用的事件有:MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_UP等 2 ...

随机推荐

  1. Spring学习之旅(六)Spring AOP工作原理初探

    AOP(Aspect-Oriented  Programming,面向切面编程)是Spring提供的关键技术之一. AOP基于IoC,是对OOP(Object-Oriented Programming ...

  2. 布局优化之ViewStub源码分析

    源码分析 @RemoteView public final class ViewStub extends View { private int mInflatedId; private int mLa ...

  3. Flask路由与蓝图Blueprint

    需求分析: 当一个庞大的系统中有很多小模块,在分配路由的时候怎么处理呢?全部都堆到一个py程序中,调用@app.route? 显然这是很不明智的,因为当有几十个模块需要写路由的时候,这样程序员写着写着 ...

  4. 账号配置vue版本的扫码下单以及对店铺进行装修的步骤

    新版vue配置说明文档 管理员后台: 1.配置管理-店铺配置(子账号)-扫码点餐tab页-开启vue版 2.配置管理-店铺配置(主账号)-扫码点餐tab页-开通装修配置 商家后台: 1.主账号-门店设 ...

  5. Snapshot origin volumes can be resized only while inactive: try lvchange -an

    事件现象:   最近同事在扩展VG时遇到了"Snapshot origin volumes can be resized only while inactive: try lvchange ...

  6. C#面向对象 1

    using System; using System.Collections.Generic; using System.Collections; using System.Linq; using S ...

  7. parent.fraInterface.xxxxxx

    fraInterface是自己定义的一个frame的名字,是通过在frame标签中设置name属性实现的.以上那句代码就是通过parent这个公共接口在各个frame间,也就是调用拥有同一个父亲的名为 ...

  8. shell编程 学好内功(一)

    shell 背景 什么是shell编程 高大上的解释,往往让人摸不住头脑.一句话概括就是:shell编程就是对一堆Linux命令的逻辑化处理. 为什么要会shell编程 举个简单的例子,我们做java ...

  9. {windows故障}关于WIN7故障模块StackHash_0a9e解决方法

    问题背景:我给同事重装好系统后,想用驱动精灵(网卡版)给新系统安装驱动,但是在安装驱动精灵的过程中老是出现标题的问题,windows停止工作,导致无法安装,最后看到这两个方法后,把网络适配器禁用,然后 ...

  10. 解决git push时发现有超过100M的文件时,删除文件后,发现还是提交不上去的问题

    我这里故意放了一个超过100M的文件 后续,git add ,git commit 然后,git push 此时会发现出现了错误.如果,我们再这里直接在文件系统中删除这个大的文件,然后再次提交,会发现 ...