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. 通过源码分析View的测量

    要理解View的测量,首先要了解MeasureSpec,系统在测量view的宽高时,要先确定MeasureSpec. MeasureSpec(32为int值)由两部分组成: SpecMode(高2位) ...

  2. Android Studio NDK JNI动态注册本地方法

    概述 可能大家觉得javah生成的函数名又臭又长,不太好看.这里可以提供另外一种方法来动态注册c++函数,让其根Java中的native方法关联起来. 实现 这里通过JNIEnv的Resisterna ...

  3. Android string.xml 添加特殊字符

    解决项目中在string.xml 中显示特殊符号的问题,如@号冒号等.只能考虑使用ASCII码进行显示: @号 @ :号 : 空格   以下为常见的ASCII十进制交换编码: --> <- ...

  4. JHipster开发环境安装

    本文演示如何在CentOS7上安装Jhipster以及其依赖组件. 这里采用官方推荐的Yarn安装方法,操作系统版本为CentOS 7.4. 1 安装JDK 推荐版本:OpenJDK 1.8.0-64 ...

  5. Scala并发编程【进阶】

    package com.dingxin.entrance import java.text.SimpleDateFormat import java.util.Date import scala.ac ...

  6. 洗礼灵魂,修炼python(88)-- 知识拾遗篇 —— 线程(2)/多线程爬虫

    线程(下) 7.同步锁 这个例子很经典,实话说,这个例子我是直接照搬前辈的,并不是原创,不过真的也很有意思,请看: #!usr/bin/env python #-*- coding:utf-8 -*- ...

  7. postgresql自定义类型并返回数组

    转自 https://blog.csdn.net/victor_ww/article/details/44415895 create type custom_data_type as ( id int ...

  8. MYSQL主从同步/主主同步

    一.MYSQL主从同步 注意:进行主从同步操作时需要确保DB无写操作 flush tables with read lock:   //全局读锁定,执行了命令之后所有库所有表都被锁定只读. 1.在主机 ...

  9. c/c++ 标准库 string

    c/c++ 标准库 string 标准库 string的小例子 test1~test10 #include <iostream> using namespace std; int main ...

  10. Windows Server 2016-域站点复制查询

    了解了有关站点复制概念性内容后,后续几章节我们会围绕站点复制相关内容对域控的日常复制.维护等进行简单介绍.本章为大家带来有关域控站点复制查询的相关内容,希望大家可以喜欢.站点内域控制器之间的复制拓扑由 ...